Skip to content

Commit 1dad4b6

Browse files
committed
add more comment
1 parent d3ddb85 commit 1dad4b6

File tree

1 file changed

+61
-14
lines changed

1 file changed

+61
-14
lines changed

src/librustc_const_eval/_match.rs

+61-14
Original file line numberDiff line numberDiff line change
@@ -419,34 +419,81 @@ fn all_constructors(_cx: &mut MatchCheckCtxt, pcx: PatternContext) -> Vec<Constr
419419
}
420420
}
421421

422-
fn max_slice_length<'a: 'b, 'b, 'tcx, I>(
422+
fn max_slice_length<'a, 'tcx, I>(
423423
_cx: &mut MatchCheckCtxt<'a, 'tcx>,
424424
patterns: I) -> usize
425-
where I: Iterator<Item=&'b [&'a Pattern<'tcx>]>
425+
where I: Iterator<Item=&'a Pattern<'tcx>>
426426
{
427427
// The exhaustiveness-checking paper does not include any details on
428428
// checking variable-length slice patterns. However, they are matched
429429
// by an infinite collection of fixed-length array patterns.
430430
//
431-
// To check that infinite set, we notice that for every length
432-
// larger than the length of the maximum fixed-length pattern,
433-
// only variable-length patterns apply.
431+
// Checking the infinite set directly would take an infinite amount
432+
// of time. However, it turns out that for each finite set of
433+
// patterns `P`, all sufficiently large array lengths are equivalent:
434434
//
435-
// For variable length patterns, all elements after the first
436-
// `prefix_len` but before the last `suffix_len` are matched by
437-
// the wildcard "middle" pattern, and therefore can be added/removed
438-
// without affecting the match result.
435+
// Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies
436+
// to exactly the subset `Pₜ` of `P` can be transformed to a slice
437+
// `sₘ` for each sufficiently-large length `m` that applies to exactly
438+
// the same subset of `P`.
439439
//
440-
// This means that all patterns with length at least
441-
// `max(max_fixed+1,max_prefix+max_suffix)` are equivalent, so we
442-
// only need to check patterns from that length and below.
440+
// Because of that, each witness for reachability-checking from one
441+
// of the sufficiently-large lengths can be transformed to an
442+
// equally-valid witness from any other length, so we only have
443+
// to check slice lengths from the "minimal sufficiently-large length"
444+
// and below.
445+
//
446+
// Note that the fact that there is a *single* `sₘ` for each `m`
447+
// not depending on the specific pattern in `P` is important: if
448+
// you look at the pair of patterns
449+
// `[true, ..]`
450+
// `[.., false]`
451+
// Then any slice of length ≥1 that matches one of these two
452+
// patterns can be be trivially turned to a slice of any
453+
// other length ≥1 that matches them and vice-versa - for
454+
// but the slice from length 2 `[false, true]` that matches neither
455+
// of these patterns can't be turned to a slice from length 1 that
456+
// matches neither of these patterns, so we have to consider
457+
// slices from length 2 there.
458+
//
459+
// Now, to see that that length exists and find it, observe that slice
460+
// patterns are either "fixed-length" patterns (`[_, _, _]`) or
461+
// "variable-length" patterns (`[_, .., _]`).
462+
//
463+
// For fixed-length patterns, all slices with lengths *longer* than
464+
// the pattern's length have the same outcome (of not matching), so
465+
// as long as `L` is greater than the pattern's length we can pick
466+
// any `sₘ` from that length and get the same result.
467+
//
468+
// For variable-length patterns, the situation is more complicated,
469+
// because as seen above the precise value of `sₘ` matters.
470+
//
471+
// However, for each variable-length pattern `p` with a prefix of length
472+
// `plₚ` and suffix of length `slₚ`, only the first `plₚ` and the last
473+
// `slₚ` elements are examined.
474+
//
475+
// Therefore, as long as `L` is positive (to avoid concerns about empty
476+
// types), all elements after the maximum prefix length and before
477+
// the maximum suffix length are not examined by any variable-length
478+
// pattern, and therefore can be added/removed without affecting
479+
// them - creating equivalent patterns from any sufficiently-large
480+
// length.
481+
//
482+
// Of course, if fixed-length patterns exist, we must be sure
483+
// that our length is large enough to miss them all, so
484+
// we can pick `L = max(FIXED_LEN+1 ∪ {max(PREFIX_LEN) + max(SUFFIX_LEN)})`
485+
//
486+
// for example, with the above pair of patterns, all elements
487+
// but the first and last can be added/removed, so any
488+
// witness of length ≥2 (say, `[false, false, true]`) can be
489+
// turned to a witness from any other length ≥2.
443490

444491
let mut max_prefix_len = 0;
445492
let mut max_suffix_len = 0;
446493
let mut max_fixed_len = 0;
447494

448495
for row in patterns {
449-
match *row[0].kind {
496+
match *row.kind {
450497
PatternKind::Constant { value: ConstVal::ByteStr(ref data) } => {
451498
max_fixed_len = cmp::max(max_fixed_len, data.len());
452499
}
@@ -504,7 +551,7 @@ pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
504551
let pcx = PatternContext {
505552
ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error())
506553
.unwrap_or(v[0].ty),
507-
max_slice_length: max_slice_length(cx, rows.iter().map(|r| &**r).chain(Some(v)))
554+
max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0])))
508555
};
509556

510557
debug!("is_useful_expand_first_col: pcx={:?}, expanding {:?}", pcx, v[0]);

0 commit comments

Comments
 (0)