Implement macro-based deref!() syntax for deref patterns
Stop using `box PAT` syntax for deref patterns, as it's misleading and also causes their semantics being tangled up.
This commit is contained in:
parent
2627e9f301
commit
2d633317f3
31 changed files with 123 additions and 35 deletions
|
@ -621,7 +621,9 @@ impl Pat {
|
|||
| PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)),
|
||||
|
||||
// Trivial wrappers over inner patterns.
|
||||
PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
|
||||
PatKind::Box(s) | PatKind::Deref(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => {
|
||||
s.walk(it)
|
||||
}
|
||||
|
||||
// These patterns do not contain subpatterns, skip.
|
||||
PatKind::Wild
|
||||
|
@ -792,6 +794,9 @@ pub enum PatKind {
|
|||
/// A `box` pattern.
|
||||
Box(P<Pat>),
|
||||
|
||||
/// A `deref` pattern (currently `deref!()` macro-based syntax).
|
||||
Deref(P<Pat>),
|
||||
|
||||
/// A reference pattern (e.g., `&mut (a, b)`).
|
||||
Ref(P<Pat>, Mutability),
|
||||
|
||||
|
|
|
@ -1295,6 +1295,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
|
|||
fields.flat_map_in_place(|field| vis.flat_map_pat_field(field));
|
||||
}
|
||||
PatKind::Box(inner) => vis.visit_pat(inner),
|
||||
PatKind::Deref(inner) => vis.visit_pat(inner),
|
||||
PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner),
|
||||
PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => {
|
||||
visit_opt(e1, |e| vis.visit_expr(e));
|
||||
|
|
|
@ -576,7 +576,10 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
|
|||
try_visit!(visitor.visit_path(path, pattern.id));
|
||||
walk_list!(visitor, visit_pat_field, fields);
|
||||
}
|
||||
PatKind::Box(subpattern) | PatKind::Ref(subpattern, _) | PatKind::Paren(subpattern) => {
|
||||
PatKind::Box(subpattern)
|
||||
| PatKind::Deref(subpattern)
|
||||
| PatKind::Ref(subpattern, _)
|
||||
| PatKind::Paren(subpattern) => {
|
||||
try_visit!(visitor.visit_pat(subpattern));
|
||||
}
|
||||
PatKind::Ident(_, ident, optional_subpattern) => {
|
||||
|
|
|
@ -91,6 +91,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
PatKind::Box(inner) => {
|
||||
break hir::PatKind::Box(self.lower_pat(inner));
|
||||
}
|
||||
PatKind::Deref(inner) => {
|
||||
break hir::PatKind::Deref(self.lower_pat(inner));
|
||||
}
|
||||
PatKind::Ref(inner, mutbl) => {
|
||||
break hir::PatKind::Ref(self.lower_pat(inner), *mutbl);
|
||||
}
|
||||
|
|
|
@ -413,10 +413,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
}
|
||||
}
|
||||
PatKind::Box(..) => {
|
||||
if !self.features.deref_patterns {
|
||||
// Allow box patterns under `deref_patterns`.
|
||||
gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
|
||||
}
|
||||
gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
|
||||
}
|
||||
PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => {
|
||||
gate!(
|
||||
|
@ -610,10 +607,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
};
|
||||
}
|
||||
|
||||
if !visitor.features.deref_patterns {
|
||||
// Allow box patterns under `deref_patterns`.
|
||||
gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
|
||||
}
|
||||
gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
|
||||
gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental");
|
||||
// Despite being a new feature, `where T: Trait<Assoc(): Sized>`, which is RTN syntax now,
|
||||
// used to be gated under associated_type_bounds, which are right above, so RTN needs to
|
||||
|
|
|
@ -1626,6 +1626,12 @@ impl<'a> State<'a> {
|
|||
self.word("box ");
|
||||
self.print_pat(inner);
|
||||
}
|
||||
PatKind::Deref(inner) => {
|
||||
self.word("deref!");
|
||||
self.popen();
|
||||
self.print_pat(inner);
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::Ref(inner, mutbl) => {
|
||||
self.word("&");
|
||||
if mutbl.is_mut() {
|
||||
|
|
|
@ -1015,7 +1015,7 @@ impl<'hir> Pat<'hir> {
|
|||
use PatKind::*;
|
||||
match self.kind {
|
||||
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
|
||||
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
|
||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
|
||||
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
|
||||
Slice(before, slice, after) => {
|
||||
|
@ -1042,7 +1042,7 @@ impl<'hir> Pat<'hir> {
|
|||
use PatKind::*;
|
||||
match self.kind {
|
||||
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
|
||||
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
|
||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
|
||||
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
|
||||
Slice(before, slice, after) => {
|
||||
|
@ -1185,6 +1185,9 @@ pub enum PatKind<'hir> {
|
|||
/// A `box` pattern.
|
||||
Box(&'hir Pat<'hir>),
|
||||
|
||||
/// A `deref` pattern (currently `deref!()` macro-based syntax).
|
||||
Deref(&'hir Pat<'hir>),
|
||||
|
||||
/// A reference pattern (e.g., `&mut (a, b)`).
|
||||
Ref(&'hir Pat<'hir>, Mutability),
|
||||
|
||||
|
|
|
@ -660,7 +660,9 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
|
|||
PatKind::Tuple(tuple_elements, _) => {
|
||||
walk_list!(visitor, visit_pat, tuple_elements);
|
||||
}
|
||||
PatKind::Box(ref subpattern) | PatKind::Ref(ref subpattern, _) => {
|
||||
PatKind::Box(ref subpattern)
|
||||
| PatKind::Deref(ref subpattern)
|
||||
| PatKind::Ref(ref subpattern, _) => {
|
||||
try_visit!(visitor.visit_pat(subpattern));
|
||||
}
|
||||
PatKind::Binding(_, _hir_id, ident, ref optional_subpattern) => {
|
||||
|
|
|
@ -668,7 +668,7 @@ fn resolve_local<'tcx>(
|
|||
| PatKind::TupleStruct(_, subpats, _)
|
||||
| PatKind::Tuple(subpats, _) => subpats.iter().any(|p| is_binding_pat(p)),
|
||||
|
||||
PatKind::Box(subpat) => is_binding_pat(subpat),
|
||||
PatKind::Box(subpat) | PatKind::Deref(subpat) => is_binding_pat(subpat),
|
||||
|
||||
PatKind::Ref(_, _)
|
||||
| PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..)
|
||||
|
|
|
@ -1808,6 +1808,12 @@ impl<'a> State<'a> {
|
|||
self.pclose();
|
||||
}
|
||||
}
|
||||
PatKind::Deref(inner) => {
|
||||
self.word("deref!");
|
||||
self.popen();
|
||||
self.print_pat(inner);
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::Ref(inner, mutbl) => {
|
||||
let is_range_inner = matches!(inner.kind, PatKind::Range(..));
|
||||
self.word("&");
|
||||
|
|
|
@ -463,6 +463,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
|||
}
|
||||
PatKind::Or(_)
|
||||
| PatKind::Box(_)
|
||||
| PatKind::Deref(_)
|
||||
| PatKind::Ref(..)
|
||||
| PatKind::Wild
|
||||
| PatKind::Err(_) => {
|
||||
|
|
|
@ -719,7 +719,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
|||
self.cat_pattern_(place_with_id, subpat, op)?;
|
||||
}
|
||||
|
||||
PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
|
||||
PatKind::Box(subpat) | PatKind::Ref(subpat, _) | PatKind::Deref(subpat) => {
|
||||
// box p1, &p1, &mut p1. we can ignore the mutability of
|
||||
// PatKind::Ref since that information is already contained
|
||||
// in the type.
|
||||
|
|
|
@ -210,10 +210,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
PatKind::Tuple(elements, ddpos) => {
|
||||
self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
|
||||
}
|
||||
PatKind::Box(inner) if self.tcx.features().deref_patterns => {
|
||||
self.check_pat_deref(pat.span, inner, expected, pat_info)
|
||||
}
|
||||
PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
|
||||
PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
|
||||
PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
|
||||
PatKind::Slice(before, slice, after) => {
|
||||
self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
|
||||
|
@ -297,6 +295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| PatKind::TupleStruct(..)
|
||||
| PatKind::Tuple(..)
|
||||
| PatKind::Box(_)
|
||||
| PatKind::Deref(_)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Slice(..) => AdjustMode::Peel,
|
||||
// A never pattern behaves somewhat like a literal or unit variant.
|
||||
|
@ -762,6 +761,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| PatKind::Binding(..)
|
||||
| PatKind::Path(..)
|
||||
| PatKind::Box(..)
|
||||
| PatKind::Deref(_)
|
||||
| PatKind::Ref(..)
|
||||
| PatKind::Lit(..)
|
||||
| PatKind::Range(..)
|
||||
|
|
|
@ -1183,7 +1183,7 @@ impl EarlyLintPass for UnusedParens {
|
|||
self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space);
|
||||
},
|
||||
// Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
|
||||
Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
|
||||
Ident(.., Some(p)) | Box(p) | Deref(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
|
||||
// Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
|
||||
// Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
|
||||
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
|
||||
|
|
|
@ -1179,7 +1179,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
|
|||
write!(f, "{subpattern}")
|
||||
}
|
||||
PatKind::DerefPattern { ref subpattern } => {
|
||||
write!(f, "k#deref {subpattern}")
|
||||
write!(f, "deref!({subpattern})")
|
||||
}
|
||||
PatKind::Constant { value } => write!(f, "{value}"),
|
||||
PatKind::InlineConstant { def: _, ref subpattern } => {
|
||||
|
|
|
@ -257,7 +257,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
return self.lower_path(qpath, pat.hir_id, pat.span);
|
||||
}
|
||||
|
||||
hir::PatKind::Box(subpattern) if self.tcx.features().deref_patterns => {
|
||||
hir::PatKind::Deref(subpattern) => {
|
||||
PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern) }
|
||||
}
|
||||
hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => {
|
||||
|
|
|
@ -498,11 +498,14 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
PatKind::Lit(const_expr)
|
||||
}
|
||||
} else if self.is_builtin() {
|
||||
self.parse_pat_builtin()?
|
||||
}
|
||||
// Don't eagerly error on semantically invalid tokens when matching
|
||||
// declarative macros, as the input to those doesn't have to be
|
||||
// semantically valid. For attribute/derive proc macros this is not the
|
||||
// case, so doing the recovery for them is fine.
|
||||
} else if self.can_be_ident_pat()
|
||||
else if self.can_be_ident_pat()
|
||||
|| (self.is_lit_bad_ident().is_some() && self.may_recover())
|
||||
{
|
||||
// Parse `ident @ pat`
|
||||
|
@ -1119,6 +1122,21 @@ impl<'a> Parser<'a> {
|
|||
.contains(&self.token.kind)
|
||||
}
|
||||
|
||||
fn parse_pat_builtin(&mut self) -> PResult<'a, PatKind> {
|
||||
self.parse_builtin(|self_, _lo, ident| {
|
||||
Ok(match ident.name {
|
||||
// builtin#deref(PAT)
|
||||
sym::deref => Some(ast::PatKind::Deref(self_.parse_pat_allow_top_alt(
|
||||
None,
|
||||
RecoverComma::Yes,
|
||||
RecoverColon::Yes,
|
||||
CommaRecoveryMode::LikelyTuple,
|
||||
)?)),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses `box pat`
|
||||
fn parse_pat_box(&mut self) -> PResult<'a, PatKind> {
|
||||
let box_span = self.prev_token.span;
|
||||
|
|
|
@ -300,6 +300,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
|||
Path,
|
||||
Tuple,
|
||||
Box,
|
||||
Deref,
|
||||
Ref,
|
||||
Lit,
|
||||
Range,
|
||||
|
@ -566,6 +567,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
|||
Path,
|
||||
Tuple,
|
||||
Box,
|
||||
Deref,
|
||||
Ref,
|
||||
Lit,
|
||||
Range,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue