@@ -3,6 +3,7 @@ use std::cmp;
3
3
use rustc_middle:: ty:: error:: TypeError ;
4
4
5
5
// An issue that might be found in the compatibility matrix
6
+ #[ derive( Debug ) ]
6
7
enum Issue {
7
8
/// The given argument is the invalid type for the input
8
9
Invalid ( usize ) ,
@@ -23,9 +24,10 @@ pub(crate) enum Compatibility<'tcx> {
23
24
}
24
25
25
26
/// Similar to `Issue`, but contains some extra information
27
+ #[ derive( Debug ) ]
26
28
pub ( crate ) enum Error < ' tcx > {
27
- /// The given argument is the invalid type for the input
28
- Invalid ( usize , Compatibility < ' tcx > ) ,
29
+ /// The provided argument is the invalid type for the expected input
30
+ Invalid ( usize , usize , Compatibility < ' tcx > ) , // provided, expected
29
31
/// There is a missing input
30
32
Missing ( usize ) ,
31
33
/// There's a superfluous argument
@@ -37,8 +39,15 @@ pub(crate) enum Error<'tcx> {
37
39
}
38
40
39
41
pub ( crate ) struct ArgMatrix < ' tcx > {
42
+ /// Maps the indices in the `compatibility_matrix` rows to the indices of
43
+ /// the *user provided* inputs
40
44
input_indexes : Vec < usize > ,
45
+ /// Maps the indices in the `compatibility_matrix` columns to the indices
46
+ /// of the *expected* args
41
47
arg_indexes : Vec < usize > ,
48
+ /// The first dimension (rows) are the remaining user provided inputs to
49
+ /// match and the second dimension (cols) are the remaining expected args
50
+ /// to match
42
51
compatibility_matrix : Vec < Vec < Compatibility < ' tcx > > > ,
43
52
}
44
53
@@ -52,24 +61,24 @@ impl<'tcx> ArgMatrix<'tcx> {
52
61
. map ( |i| ( 0 ..minimum_input_count) . map ( |j| is_compatible ( i, j) ) . collect ( ) )
53
62
. collect ( ) ;
54
63
ArgMatrix {
55
- input_indexes : ( 0 ..minimum_input_count ) . collect ( ) ,
56
- arg_indexes : ( 0 ..provided_arg_count ) . collect ( ) ,
64
+ input_indexes : ( 0 ..provided_arg_count ) . collect ( ) ,
65
+ arg_indexes : ( 0 ..minimum_input_count ) . collect ( ) ,
57
66
compatibility_matrix,
58
67
}
59
68
}
60
69
61
70
/// Remove a given input from consideration
62
71
fn eliminate_input ( & mut self , idx : usize ) {
63
72
self . input_indexes . remove ( idx) ;
64
- for row in & mut self . compatibility_matrix {
65
- row. remove ( idx) ;
66
- }
73
+ self . compatibility_matrix . remove ( idx) ;
67
74
}
68
75
69
76
/// Remove a given argument from consideration
70
77
fn eliminate_arg ( & mut self , idx : usize ) {
71
78
self . arg_indexes . remove ( idx) ;
72
- self . compatibility_matrix . remove ( idx) ;
79
+ for row in & mut self . compatibility_matrix {
80
+ row. remove ( idx) ;
81
+ }
73
82
}
74
83
75
84
/// "satisfy" an input with a given arg, removing both from consideration
@@ -78,21 +87,23 @@ impl<'tcx> ArgMatrix<'tcx> {
78
87
self . eliminate_arg ( arg_idx) ;
79
88
}
80
89
90
+ // Returns a `Vec` of (user input, expected arg) of matched arguments. These
91
+ // are inputs on the remaining diagonal that match.
81
92
fn eliminate_satisfied ( & mut self ) -> Vec < ( usize , usize ) > {
82
93
let mut i = cmp:: min ( self . input_indexes . len ( ) , self . arg_indexes . len ( ) ) ;
83
94
let mut eliminated = vec ! [ ] ;
84
95
while i > 0 {
85
96
let idx = i - 1 ;
86
97
if matches ! ( self . compatibility_matrix[ idx] [ idx] , Compatibility :: Compatible ) {
87
- eliminated. push ( ( self . arg_indexes [ idx] , self . input_indexes [ idx] ) ) ;
98
+ eliminated. push ( ( self . input_indexes [ idx] , self . arg_indexes [ idx] ) ) ;
88
99
self . satisfy_input ( idx, idx) ;
89
100
}
90
101
i -= 1 ;
91
102
}
92
103
return eliminated;
93
104
}
94
105
95
- // Check for the above mismatch cases
106
+ // Find some issue in the compatibility matrix
96
107
fn find_issue ( & self ) -> Option < Issue > {
97
108
let mat = & self . compatibility_matrix ;
98
109
let ai = & self . arg_indexes ;
@@ -121,26 +132,26 @@ impl<'tcx> ArgMatrix<'tcx> {
121
132
if is_arg {
122
133
for j in 0 ..ii. len ( ) {
123
134
// If we find at least one input this argument could satisfy
124
- // this argument isn't completely useless
125
- if matches ! ( mat[ i ] [ j ] , Compatibility :: Compatible ) {
126
- useless = false ;
135
+ // this argument isn't unsatisfiable
136
+ if matches ! ( mat[ j ] [ i ] , Compatibility :: Compatible ) {
137
+ unsatisfiable = false ;
127
138
break ;
128
139
}
129
140
}
130
141
}
131
142
if is_input {
132
143
for j in 0 ..ai. len ( ) {
133
144
// If we find at least one argument that could satisfy this input
134
- // this argument isn't unsatisfiable
135
- if matches ! ( mat[ j ] [ i ] , Compatibility :: Compatible ) {
136
- unsatisfiable = false ;
145
+ // this argument isn't useless
146
+ if matches ! ( mat[ i ] [ j ] , Compatibility :: Compatible ) {
147
+ useless = false ;
137
148
break ;
138
149
}
139
150
}
140
151
}
141
152
142
- match ( is_arg , is_input , useless, unsatisfiable) {
143
- // If an input is unsatisfied, and the argument in its position is useless
153
+ match ( is_input , is_arg , useless, unsatisfiable) {
154
+ // If an argument is unsatisfied, and the input in its position is useless
144
155
// then the most likely explanation is that we just got the types wrong
145
156
( true , true , true , true ) => return Some ( Issue :: Invalid ( i) ) ,
146
157
// Otherwise, if an input is useless, then indicate that this is an extra argument
@@ -167,7 +178,7 @@ impl<'tcx> ArgMatrix<'tcx> {
167
178
_ => {
168
179
continue ;
169
180
}
170
- } ;
181
+ }
171
182
}
172
183
173
184
// We didn't find any of the individual issues above, but
@@ -254,11 +265,11 @@ impl<'tcx> ArgMatrix<'tcx> {
254
265
// We'll want to know which arguments and inputs these rows and columns correspond to
255
266
// even after we delete them.
256
267
pub ( crate ) fn find_errors ( mut self ) -> ( Vec < Error < ' tcx > > , Vec < Option < usize > > ) {
257
- let provided_arg_count = self . arg_indexes . len ( ) ;
268
+ let provided_arg_count = self . input_indexes . len ( ) ;
258
269
259
270
let mut errors: Vec < Error < ' tcx > > = vec ! [ ] ;
260
271
// For each expected argument, the matched *actual* input
261
- let mut matched_inputs: Vec < Option < usize > > = vec ! [ None ; self . input_indexes . len( ) ] ;
272
+ let mut matched_inputs: Vec < Option < usize > > = vec ! [ None ; self . arg_indexes . len( ) ] ;
262
273
263
274
// Before we start looking for issues, eliminate any arguments that are already satisfied,
264
275
// so that an argument which is already spoken for by the input it's in doesn't
@@ -269,28 +280,28 @@ impl<'tcx> ArgMatrix<'tcx> {
269
280
// Without this elimination, the first argument causes the second argument
270
281
// to show up as both a missing input and extra argument, rather than
271
282
// just an invalid type.
272
- for ( arg , inp ) in self . eliminate_satisfied ( ) {
273
- matched_inputs[ inp ] = Some ( arg ) ;
283
+ for ( inp , arg ) in self . eliminate_satisfied ( ) {
284
+ matched_inputs[ arg ] = Some ( inp ) ;
274
285
}
275
286
276
287
while self . input_indexes . len ( ) > 0 || self . arg_indexes . len ( ) > 0 {
277
- // Check for the first relevant issue
278
288
match self . find_issue ( ) {
279
289
Some ( Issue :: Invalid ( idx) ) => {
280
290
let compatibility = self . compatibility_matrix [ idx] [ idx] . clone ( ) ;
281
291
let input_idx = self . input_indexes [ idx] ;
292
+ let arg_idx = self . arg_indexes [ idx] ;
282
293
self . satisfy_input ( idx, idx) ;
283
- errors. push ( Error :: Invalid ( input_idx, compatibility) ) ;
294
+ errors. push ( Error :: Invalid ( input_idx, arg_idx , compatibility) ) ;
284
295
}
285
296
Some ( Issue :: Extra ( idx) ) => {
286
- let arg_idx = self . arg_indexes [ idx] ;
287
- self . eliminate_arg ( idx) ;
288
- errors. push ( Error :: Extra ( arg_idx) ) ;
289
- }
290
- Some ( Issue :: Missing ( idx) ) => {
291
297
let input_idx = self . input_indexes [ idx] ;
292
298
self . eliminate_input ( idx) ;
293
- errors. push ( Error :: Missing ( input_idx) ) ;
299
+ errors. push ( Error :: Extra ( input_idx) ) ;
300
+ }
301
+ Some ( Issue :: Missing ( idx) ) => {
302
+ let arg_idx = self . arg_indexes [ idx] ;
303
+ self . eliminate_arg ( idx) ;
304
+ errors. push ( Error :: Missing ( arg_idx) ) ;
294
305
}
295
306
Some ( Issue :: Swap ( idx, other) ) => {
296
307
let input_idx = self . input_indexes [ idx] ;
@@ -302,24 +313,21 @@ impl<'tcx> ArgMatrix<'tcx> {
302
313
// Subtract 1 because we already removed the "min" row
303
314
self . satisfy_input ( max - 1 , min) ;
304
315
errors. push ( Error :: Swap ( input_idx, other_input_idx, arg_idx, other_arg_idx) ) ;
305
- matched_inputs[ input_idx ] = Some ( other_arg_idx ) ;
306
- matched_inputs[ other_input_idx ] = Some ( arg_idx ) ;
316
+ matched_inputs[ other_arg_idx ] = Some ( input_idx ) ;
317
+ matched_inputs[ arg_idx ] = Some ( other_input_idx ) ;
307
318
}
308
319
Some ( Issue :: Permutation ( args) ) => {
309
- // FIXME: If satisfy_input ever did anything non-trivial (emit obligations to help type checking, for example)
310
- // we'd want to call this function with the correct arg/input pairs, but for now, we just throw them in a bucket.
311
- // This works because they force a cycle, so each row is guaranteed to also be a column
312
320
let mut idxs: Vec < usize > = args. iter ( ) . filter_map ( |& a| a) . collect ( ) ;
313
321
314
322
let mut real_idxs = vec ! [ None ; provided_arg_count] ;
315
323
for ( src, dst) in
316
324
args. iter ( ) . enumerate ( ) . filter_map ( |( src, dst) | dst. map ( |dst| ( src, dst) ) )
317
325
{
318
- let src_arg = self . arg_indexes [ src] ;
319
- let dst_arg = self . arg_indexes [ dst] ;
320
- let dest_input = self . input_indexes [ dst] ;
321
- real_idxs[ src_arg ] = Some ( ( dst_arg , dest_input ) ) ;
322
- matched_inputs[ dest_input ] = Some ( src_arg ) ;
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] ;
329
+ real_idxs[ src_input_idx ] = Some ( ( dest_arg_idx , dst_input_idx ) ) ;
330
+ matched_inputs[ dest_arg_idx ] = Some ( src_input_idx ) ;
323
331
}
324
332
idxs. sort ( ) ;
325
333
idxs. reverse ( ) ;
@@ -331,8 +339,8 @@ impl<'tcx> ArgMatrix<'tcx> {
331
339
None => {
332
340
// We didn't find any issues, so we need to push the algorithm forward
333
341
// First, eliminate any arguments that currently satisfy their inputs
334
- for ( arg , inp ) in self . eliminate_satisfied ( ) {
335
- matched_inputs[ inp ] = Some ( arg ) ;
342
+ for ( inp , arg ) in self . eliminate_satisfied ( ) {
343
+ matched_inputs[ arg ] = Some ( inp ) ;
336
344
}
337
345
}
338
346
} ;
0 commit comments