Clarify specialization into two steps
First is checking for constructor overlap, second is extracting the resulting fields.
This commit is contained in:
parent
7c4f94be48
commit
6ad9f44a50
1 changed files with 48 additions and 56 deletions
|
@ -2527,9 +2527,9 @@ fn pat_constructor<'tcx>(
|
||||||
fn specialize_one_pattern<'p, 'tcx>(
|
fn specialize_one_pattern<'p, 'tcx>(
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||||
pat: &'p Pat<'tcx>,
|
pat: &'p Pat<'tcx>,
|
||||||
constructor: &Constructor<'tcx>,
|
ctor: &Constructor<'tcx>,
|
||||||
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
||||||
is_its_own_ctor: bool, // Whether `constructor` is known to be derived from `pat`
|
is_its_own_ctor: bool, // Whether `ctor` is known to be derived from `pat`
|
||||||
) -> Option<Fields<'p, 'tcx>> {
|
) -> Option<Fields<'p, 'tcx>> {
|
||||||
if pat.is_wildcard() {
|
if pat.is_wildcard() {
|
||||||
return Some(ctor_wild_subpatterns.clone());
|
return Some(ctor_wild_subpatterns.clone());
|
||||||
|
@ -2539,57 +2539,34 @@ fn specialize_one_pattern<'p, 'tcx>(
|
||||||
// `unwrap` is safe because `pat` is not a wildcard.
|
// `unwrap` is safe because `pat` is not a wildcard.
|
||||||
let pat_ctor = pat_constructor(cx.tcx, cx.param_env, pat).unwrap();
|
let pat_ctor = pat_constructor(cx.tcx, cx.param_env, pat).unwrap();
|
||||||
|
|
||||||
let result = match (constructor, &pat_ctor, pat.kind.as_ref()) {
|
let ctor_covered_by_pat = match (ctor, &pat_ctor) {
|
||||||
(Single, Single, PatKind::Leaf { subpatterns }) => {
|
(Single, Single) => true,
|
||||||
Some(ctor_wild_subpatterns.replace_with_fieldpats(subpatterns))
|
(Variant(ctor_id), Variant(pat_id)) => ctor_id == pat_id,
|
||||||
}
|
|
||||||
(Single, Single, PatKind::Deref { subpattern }) => {
|
|
||||||
Some(Fields::from_single_pattern(subpattern))
|
|
||||||
}
|
|
||||||
(Variant(_), Variant(_), _) if constructor != &pat_ctor => None,
|
|
||||||
(Variant(_), Variant(_), PatKind::Variant { subpatterns, .. }) => {
|
|
||||||
Some(ctor_wild_subpatterns.replace_with_fieldpats(subpatterns))
|
|
||||||
}
|
|
||||||
|
|
||||||
(IntRange(ctor_range), IntRange(pat_range), _) => {
|
(IntRange(ctor_range), IntRange(pat_range)) => {
|
||||||
ctor_range.intersection(cx.tcx, &pat_range)?;
|
if ctor_range.intersection(cx.tcx, pat_range).is_some() {
|
||||||
// Constructor splitting should ensure that all intersections we encounter
|
// Constructor splitting should ensure that all intersections we encounter
|
||||||
// are actually inclusions.
|
// are actually inclusions.
|
||||||
assert!(ctor_range.is_subrange(&pat_range));
|
assert!(ctor_range.is_subrange(pat_range));
|
||||||
Some(Fields::empty())
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(FloatRange(ctor_from, ctor_to, ctor_end), FloatRange(pat_from, pat_to, pat_end), _) => {
|
(FloatRange(ctor_from, ctor_to, ctor_end), FloatRange(pat_from, pat_to, pat_end)) => {
|
||||||
let to = compare_const_vals(cx.tcx, ctor_to, pat_to, cx.param_env, ty)?;
|
let to = compare_const_vals(cx.tcx, ctor_to, pat_to, cx.param_env, ty)?;
|
||||||
let from = compare_const_vals(cx.tcx, ctor_from, pat_from, cx.param_env, ty)?;
|
let from = compare_const_vals(cx.tcx, ctor_from, pat_from, cx.param_env, ty)?;
|
||||||
let intersects = (from == Ordering::Greater || from == Ordering::Equal)
|
(from == Ordering::Greater || from == Ordering::Equal)
|
||||||
&& (to == Ordering::Less || (pat_end == ctor_end && to == Ordering::Equal));
|
&& (to == Ordering::Less || (pat_end == ctor_end && to == Ordering::Equal))
|
||||||
if intersects { Some(Fields::empty()) } else { None }
|
|
||||||
}
|
}
|
||||||
(Str(ctor_val), Str(pat_val), _) => {
|
(Str(ctor_val), Str(pat_val)) => {
|
||||||
// FIXME: there's probably a more direct way of comparing for equality
|
// FIXME: there's probably a more direct way of comparing for equality
|
||||||
let comparison = compare_const_vals(cx.tcx, ctor_val, pat_val, cx.param_env, ty)?;
|
let comparison = compare_const_vals(cx.tcx, ctor_val, pat_val, cx.param_env, ty)?;
|
||||||
if comparison == Ordering::Equal { Some(Fields::empty()) } else { None }
|
comparison == Ordering::Equal
|
||||||
}
|
}
|
||||||
|
|
||||||
(Slice(ctor_slice), Slice(pat_slice), _)
|
(Slice(ctor_slice), Slice(pat_slice)) => {
|
||||||
if !pat_slice.pattern_kind().covers_length(ctor_slice.arity()) =>
|
pat_slice.pattern_kind().covers_length(ctor_slice.arity())
|
||||||
{
|
|
||||||
None
|
|
||||||
}
|
|
||||||
(
|
|
||||||
Slice(ctor_slice),
|
|
||||||
Slice(_),
|
|
||||||
PatKind::Array { prefix, suffix, .. } | PatKind::Slice { prefix, suffix, .. },
|
|
||||||
) => {
|
|
||||||
// Number of subpatterns for the constructor
|
|
||||||
let ctor_arity = ctor_slice.arity();
|
|
||||||
|
|
||||||
// Replace the prefix and the suffix with the given patterns, leaving wildcards in
|
|
||||||
// the middle if there was a subslice pattern `..`.
|
|
||||||
let prefix = prefix.iter().enumerate();
|
|
||||||
let suffix =
|
|
||||||
suffix.iter().enumerate().map(|(i, p)| (ctor_arity as usize - suffix.len() + i, p));
|
|
||||||
Some(ctor_wild_subpatterns.replace_fields_indexed(prefix.chain(suffix)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only a wildcard pattern can match an opaque constant, unless we're specializing the
|
// Only a wildcard pattern can match an opaque constant, unless we're specializing the
|
||||||
|
@ -2611,23 +2588,38 @@ fn specialize_one_pattern<'p, 'tcx>(
|
||||||
// (FOO, false) => {}
|
// (FOO, false) => {}
|
||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
(Opaque, Opaque, _) if is_its_own_ctor => Some(Fields::empty()),
|
(Opaque, Opaque) if is_its_own_ctor => true,
|
||||||
// We are trying to inspect an opaque constant. Thus we skip the row.
|
// We are trying to inspect an opaque constant. Thus we skip the row.
|
||||||
(Opaque, _, _) | (_, Opaque, _) => None,
|
(Opaque, _) | (_, Opaque) => false,
|
||||||
// Only a wildcard pattern can match the special extra constructor.
|
// Only a wildcard pattern can match the special extra constructor.
|
||||||
(NonExhaustive, _, _) => None,
|
(NonExhaustive, _) => false,
|
||||||
|
|
||||||
_ => bug!("trying to specialize pattern {:?} with constructor {:?}", pat, constructor),
|
_ => bug!("trying to specialize pattern {:?} with constructor {:?}", pat, ctor),
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!(
|
if !ctor_covered_by_pat {
|
||||||
"specialize({:#?}, {:#?}, {:#?}) = {:#?}",
|
return None;
|
||||||
pat, constructor, ctor_wild_subpatterns, result
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(fields) = &result {
|
|
||||||
debug_assert_eq!(fields.len(), ctor_wild_subpatterns.len());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
let fields = match pat.kind.as_ref() {
|
||||||
|
PatKind::Deref { subpattern } => Fields::from_single_pattern(subpattern),
|
||||||
|
PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
|
||||||
|
ctor_wild_subpatterns.replace_with_fieldpats(subpatterns)
|
||||||
|
}
|
||||||
|
PatKind::Array { prefix, suffix, .. } | PatKind::Slice { prefix, suffix, .. } => {
|
||||||
|
// Number of subpatterns for the constructor
|
||||||
|
let ctor_arity = ctor_wild_subpatterns.len();
|
||||||
|
|
||||||
|
// Replace the prefix and the suffix with the given patterns, leaving wildcards in
|
||||||
|
// the middle if there was a subslice pattern `..`.
|
||||||
|
let prefix = prefix.iter().enumerate();
|
||||||
|
let suffix = suffix.iter().enumerate().map(|(i, p)| (ctor_arity - suffix.len() + i, p));
|
||||||
|
ctor_wild_subpatterns.replace_fields_indexed(prefix.chain(suffix))
|
||||||
|
}
|
||||||
|
_ => ctor_wild_subpatterns.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("specialize({:#?}, {:#?}, {:#?}) = {:#?}", pat, ctor, ctor_wild_subpatterns, fields);
|
||||||
|
|
||||||
|
Some(fields)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue