提交 5853399a 编写于 作者: N Nadrieril

Move special `&str` handling to `Constructor` and `Fields`

上级 035c5213
......@@ -660,9 +660,10 @@ pub(super) fn from_pat<'p>(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &'p Pat<'tcx>) ->
} else {
match pat.ty.kind() {
ty::Float(_) => FloatRange(value, value, RangeEnd::Included),
// In `expand_pattern`, we convert string literals to `&CONST` patterns with
// `CONST` a pattern of type `str`. In truth this contains a constant of type
// `&str`.
// We make `&str` constants behave like `Deref` patterns, to be compatible
// with other `Deref` patterns. See also `Fields::extract_pattern_arguments`.
ty::Ref(_, t, _) if t.is_str() => Single,
// In truth this carries a constant of type `&str`.
ty::Str => Str(value),
// All constants that can be structurally matched have already been expanded
// into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
......@@ -1393,6 +1394,19 @@ pub(super) fn extract_pattern_arguments(
self.fields[i] = pat
}
}
PatKind::Constant { .. } => match pat.ty.kind() {
ty::Ref(_, t, _) if t.is_str() => {
assert_eq!(self.len(), 1);
// We want a `&str` constant to behave like a `Deref` pattern, to be compatible
// with other `Deref` patterns. This could have been done in `const_to_pat`,
// but that causes issues with the rest of the matching code.
// The outer constructor is `&`, and the inner one carries the str value.
let mut new_pat = pat.clone();
new_pat.ty = t; // `t` is `str`, not `&str`
self.fields[0] = &*cx.pattern_arena.alloc(new_pat);
}
_ => {}
},
_ => {}
};
self
......
......@@ -365,23 +365,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> {
debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind);
match (pat.ty.kind(), pat.kind.as_ref()) {
(_, PatKind::Binding { subpattern: Some(s), .. }) => s.fold_with(self),
(_, PatKind::AscribeUserType { subpattern: s, .. }) => s.fold_with(self),
(ty::Ref(_, t, _), PatKind::Constant { .. }) if t.is_str() => {
// Treat string literal patterns as deref patterns to a `str` constant, i.e.
// `&CONST`. This expands them like other const patterns. This could have been done
// in `const_to_pat`, but that causes issues with the rest of the matching code.
let mut new_pat = pat.super_fold_with(self);
// Make a fake const pattern of type `str` (instead of `&str`). That the carried
// constant value still knows it is of type `&str`.
new_pat.ty = t;
Pat {
kind: Box::new(PatKind::Deref { subpattern: new_pat }),
span: pat.span,
ty: pat.ty,
}
}
match pat.kind.as_ref() {
PatKind::Binding { subpattern: Some(s), .. } => s.fold_with(self),
PatKind::AscribeUserType { subpattern: s, .. } => s.fold_with(self),
_ => pat.super_fold_with(self),
}
}
......@@ -1183,7 +1169,7 @@ fn is_useful<'p, 'tcx>(
let ctor_wild_subpatterns = Fields::wildcards(pcx.cx, pcx.ty, &ctor);
let spec_matrix =
start_matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
let v = v.pop_head_constructor(pcx.cx, &ctor_wild_subpatterns);
let v = v.pop_head_constructor(cx, &ctor_wild_subpatterns);
let usefulness =
is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false);
let usefulness =
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册