1
1
use std:: cmp;
2
2
3
+ use rustc_index:: vec:: IndexVec ;
3
4
use rustc_middle:: ty:: error:: TypeError ;
4
5
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
+
5
24
// An issue that might be found in the compatibility matrix
6
25
#[ derive( Debug ) ]
7
26
enum Issue {
@@ -27,87 +46,89 @@ pub(crate) enum Compatibility<'tcx> {
27
46
#[ derive( Debug ) ]
28
47
pub ( crate ) enum Error < ' tcx > {
29
48
/// 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 > ) ,
31
50
/// There is a missing input
32
- Missing ( usize ) ,
51
+ Missing ( ExpectedIdx ) ,
33
52
/// There's a superfluous argument
34
- Extra ( usize ) ,
53
+ Extra ( ProvidedIdx ) ,
35
54
/// Two arguments should be swapped
36
- Swap ( usize , usize , usize , usize ) ,
55
+ Swap ( ProvidedIdx , ProvidedIdx , ExpectedIdx , ExpectedIdx ) ,
37
56
/// Several arguments should be reordered
38
- Permutation ( Vec < ( usize , usize ) > ) , // dest_arg, dest_input
57
+ Permutation ( Vec < ( ExpectedIdx , ProvidedIdx ) > ) ,
39
58
}
40
59
41
60
pub ( crate ) struct ArgMatrix < ' tcx > {
42
61
/// Maps the indices in the `compatibility_matrix` rows to the indices of
43
62
/// the *user provided* inputs
44
- input_indexes : Vec < usize > ,
63
+ provided_indices : Vec < ProvidedIdx > ,
45
64
/// Maps the indices in the `compatibility_matrix` columns to the indices
46
65
/// of the *expected* args
47
- arg_indexes : Vec < usize > ,
66
+ expected_indices : Vec < ExpectedIdx > ,
48
67
/// The first dimension (rows) are the remaining user provided inputs to
49
68
/// match and the second dimension (cols) are the remaining expected args
50
69
/// to match
51
70
compatibility_matrix : Vec < Vec < Compatibility < ' tcx > > > ,
52
71
}
53
72
54
73
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 ,
58
77
mut is_compatible : F ,
59
78
) -> 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
+ } )
62
85
. collect ( ) ;
63
86
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 ( ) ,
66
89
compatibility_matrix,
67
90
}
68
91
}
69
92
70
93
/// 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) ;
73
96
self . compatibility_matrix . remove ( idx) ;
74
97
}
75
98
76
99
/// 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) ;
79
102
for row in & mut self . compatibility_matrix {
80
103
row. remove ( idx) ;
81
104
}
82
105
}
83
106
84
107
/// "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 ) ;
88
111
}
89
112
90
113
// Returns a `Vec` of (user input, expected arg) of matched arguments. These
91
114
// 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 ( ) ) ;
94
117
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) ;
100
122
}
101
- i -= 1 ;
102
123
}
103
- return eliminated;
124
+ eliminated
104
125
}
105
126
106
127
// Find some issue in the compatibility matrix
107
128
fn find_issue ( & self ) -> Option < Issue > {
108
129
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 ;
111
132
112
133
for i in 0 ..cmp:: max ( ai. len ( ) , ii. len ( ) ) {
113
134
// If we eliminate the last row, any left-over inputs are considered missing
@@ -264,12 +285,15 @@ impl<'tcx> ArgMatrix<'tcx> {
264
285
//
265
286
// We'll want to know which arguments and inputs these rows and columns correspond to
266
287
// 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 ( ) ;
269
292
270
293
let mut errors: Vec < Error < ' tcx > > = vec ! [ ] ;
271
294
// 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 ( ) ) ;
273
297
274
298
// Before we start looking for issues, eliminate any arguments that are already satisfied,
275
299
// 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> {
280
304
// Without this elimination, the first argument causes the second argument
281
305
// to show up as both a missing input and extra argument, rather than
282
306
// 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 ) ;
285
309
}
286
310
287
- while self . input_indexes . len ( ) > 0 || self . arg_indexes . len ( ) > 0 {
311
+ while ! self . provided_indices . is_empty ( ) || ! self . expected_indices . is_empty ( ) {
288
312
match self . find_issue ( ) {
289
313
Some ( Issue :: Invalid ( idx) ) => {
290
314
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] ;
293
317
self . satisfy_input ( idx, idx) ;
294
318
errors. push ( Error :: Invalid ( input_idx, arg_idx, compatibility) ) ;
295
319
}
296
320
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) ;
299
323
errors. push ( Error :: Extra ( input_idx) ) ;
300
324
}
301
325
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) ;
304
328
errors. push ( Error :: Missing ( arg_idx) ) ;
305
329
}
306
330
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] ;
311
335
let ( min, max) = ( cmp:: min ( idx, other) , cmp:: max ( idx, other) ) ;
312
336
self . satisfy_input ( min, max) ;
313
337
// Subtract 1 because we already removed the "min" row
@@ -319,13 +343,14 @@ impl<'tcx> ArgMatrix<'tcx> {
319
343
Some ( Issue :: Permutation ( args) ) => {
320
344
let mut idxs: Vec < usize > = args. iter ( ) . filter_map ( |& a| a) . collect ( ) ;
321
345
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) ;
323
348
for ( src, dst) in
324
349
args. iter ( ) . enumerate ( ) . filter_map ( |( src, dst) | dst. map ( |dst| ( src, dst) ) )
325
350
{
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] ;
329
354
real_idxs[ src_input_idx] = Some ( ( dest_arg_idx, dst_input_idx) ) ;
330
355
matched_inputs[ dest_arg_idx] = Some ( src_input_idx) ;
331
356
}
0 commit comments