Inline specialize_one_pattern
This commit is contained in:
parent
c511955a9f
commit
41e7ca499d
1 changed files with 39 additions and 51 deletions
|
@ -407,20 +407,51 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This computes `S(constructor, self)`. See top of the file for explanations.
|
/// This computes `S(constructor, self)`. See top of the file for explanations.
|
||||||
|
///
|
||||||
|
/// This is the main specialization step. It expands the pattern
|
||||||
|
/// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
|
||||||
|
/// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
|
||||||
|
/// Returns `None` if the pattern does not have the given constructor.
|
||||||
|
///
|
||||||
|
/// OTOH, slice patterns with a subslice pattern (tail @ ..) can be expanded into multiple
|
||||||
|
/// different patterns.
|
||||||
|
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
|
||||||
|
/// fields filled with wild patterns.
|
||||||
|
///
|
||||||
|
/// This is roughly the inverse of `Constructor::apply`.
|
||||||
fn specialize_constructor(
|
fn specialize_constructor(
|
||||||
&self,
|
&self,
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||||
constructor: &Constructor<'tcx>,
|
ctor: &Constructor<'tcx>,
|
||||||
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
||||||
is_my_head_ctor: bool,
|
is_my_head_ctor: bool,
|
||||||
) -> Option<PatStack<'p, 'tcx>> {
|
) -> Option<PatStack<'p, 'tcx>> {
|
||||||
let new_fields = specialize_one_pattern(
|
// We return `None` if `ctor` is not covered by `self.head()`. If `ctor` is known to be
|
||||||
cx,
|
// derived from `self.head()`, or if `self.head()` is a wildcard, then we don't need to
|
||||||
|
// check; otherwise, we compute the constructor of `self.head()` and check for constructor
|
||||||
|
// inclusion.
|
||||||
|
// Note that this shortcut is also necessary for correctness: a pattern should always be
|
||||||
|
// specializable with its own constructor, even in cases where we refuse to inspect values like
|
||||||
|
// opaque constants.
|
||||||
|
if !self.head().is_wildcard() && !is_my_head_ctor {
|
||||||
|
// `unwrap` is safe because `pat` is not a wildcard.
|
||||||
|
let head_ctor = pat_constructor(cx.tcx, cx.param_env, self.head()).unwrap();
|
||||||
|
if !ctor.is_covered_by(cx, &head_ctor, self.head().ty) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let new_fields = ctor_wild_subpatterns.replace_with_pattern_arguments(self.head());
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"specialize_constructor({:#?}, {:#?}, {:#?}) = {:#?}",
|
||||||
self.head(),
|
self.head(),
|
||||||
constructor,
|
ctor,
|
||||||
ctor_wild_subpatterns,
|
ctor_wild_subpatterns,
|
||||||
is_my_head_ctor,
|
new_fields
|
||||||
)?;
|
);
|
||||||
|
|
||||||
|
// We pop the head pattern and push the new fields extracted from the arguments of
|
||||||
|
// `self.head()`.
|
||||||
Some(new_fields.push_on_patstack(&self.0[1..]))
|
Some(new_fields.push_on_patstack(&self.0[1..]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -971,7 +1002,7 @@ impl Slice {
|
||||||
/// the constructor. See also `Fields`.
|
/// the constructor. See also `Fields`.
|
||||||
///
|
///
|
||||||
/// `pat_constructor` retrieves the constructor corresponding to a pattern.
|
/// `pat_constructor` retrieves the constructor corresponding to a pattern.
|
||||||
/// `specialize_one_pattern` returns the list of fields corresponding to a pattern, given a
|
/// `specialize_constructor` returns the list of fields corresponding to a pattern, given a
|
||||||
/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
|
/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
|
||||||
/// `Fields`.
|
/// `Fields`.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
@ -1195,7 +1226,7 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
/// Apply a constructor to a list of patterns, yielding a new pattern. `pats`
|
/// Apply a constructor to a list of patterns, yielding a new pattern. `pats`
|
||||||
/// must have as many elements as this constructor's arity.
|
/// must have as many elements as this constructor's arity.
|
||||||
///
|
///
|
||||||
/// This is roughly the inverse of `specialize_one_pattern`.
|
/// This is roughly the inverse of `specialize_constructor`.
|
||||||
///
|
///
|
||||||
/// Examples:
|
/// Examples:
|
||||||
/// `self`: `Constructor::Single`
|
/// `self`: `Constructor::Single`
|
||||||
|
@ -2607,46 +2638,3 @@ fn pat_constructor<'tcx>(
|
||||||
PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
|
PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is the main specialization step. It expands the pattern
|
|
||||||
/// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
|
|
||||||
/// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
|
|
||||||
/// Returns `None` if the pattern does not have the given constructor.
|
|
||||||
///
|
|
||||||
/// OTOH, slice patterns with a subslice pattern (tail @ ..) can be expanded into multiple
|
|
||||||
/// different patterns.
|
|
||||||
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
|
|
||||||
/// fields filled with wild patterns.
|
|
||||||
///
|
|
||||||
/// This is roughly the inverse of `Constructor::apply`.
|
|
||||||
fn specialize_one_pattern<'p, 'tcx>(
|
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
|
||||||
pat: &'p Pat<'tcx>,
|
|
||||||
ctor: &Constructor<'tcx>,
|
|
||||||
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
|
|
||||||
is_its_own_ctor: bool, // Whether `ctor` is known to be derived from `pat`
|
|
||||||
) -> Option<Fields<'p, 'tcx>> {
|
|
||||||
if pat.is_wildcard() {
|
|
||||||
return Some(ctor_wild_subpatterns.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// We return `None` if `ctor` is not covered by `pat`. If `ctor` is known to be derived from
|
|
||||||
// `pat` then we don't need to check; otherwise, we compute the constructor of `pat` and check
|
|
||||||
// for constructor inclusion.
|
|
||||||
// Note that this shortcut is also necessary for correctness: a pattern should always be
|
|
||||||
// specializable with its own constructor, even in cases where we refuse to inspect values like
|
|
||||||
// opaque constants.
|
|
||||||
if !is_its_own_ctor {
|
|
||||||
// `unwrap` is safe because `pat` is not a wildcard.
|
|
||||||
let pat_ctor = pat_constructor(cx.tcx, cx.param_env, pat).unwrap();
|
|
||||||
if !ctor.is_covered_by(cx, &pat_ctor, pat.ty) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let fields = ctor_wild_subpatterns.replace_with_pattern_arguments(pat);
|
|
||||||
|
|
||||||
debug!("specialize({:#?}, {:#?}, {:#?}) = {:#?}", pat, ctor, ctor_wild_subpatterns, fields);
|
|
||||||
|
|
||||||
Some(fields)
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue