Skip to content

Commit

Permalink
Implement macro-based deref_pat!() syntax for deref patterns
Browse files Browse the repository at this point in the history
Stop using `box PAT` syntax for deref patterns, as it's misleading and
also causes their semantics being tangled up.
  • Loading branch information
compiler-errors committed Mar 20, 2024
1 parent 1345c72 commit 7d50e10
Show file tree
Hide file tree
Showing 25 changed files with 107 additions and 25 deletions.
7 changes: 6 additions & 1 deletion compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -792,6 +794,9 @@ pub enum PatKind {
/// A `box` pattern.
Box(P<Pat>),

/// A `deref` pattern (currently `deref_pat!()` macro-based syntax).
Deref(P<Pat>),

/// A reference pattern (e.g., `&mut (a, b)`).
Ref(P<Pat>, Mutability),

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_ast_lowering/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
10 changes: 2 additions & 8 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand Down Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1626,6 +1626,12 @@ impl<'a> State<'a> {
self.word("box ");
self.print_pat(inner);
}
PatKind::Deref(inner) => {
self.word("deref_pat!");
self.popen();
self.print_pat(inner);
self.pclose();
}
PatKind::Ref(inner, mutbl) => {
self.word("&");
if mutbl.is_mut() {
Expand Down
23 changes: 23 additions & 0 deletions compiler/rustc_builtin_macros/src/deref_pat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use rustc_ast as ast;
use rustc_ast::tokenstream::TokenStream;
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_parse::parser::{CommaRecoveryMode, RecoverColon, RecoverComma};
use rustc_span::Span;

pub fn expand_deref_pat(
cx: &mut ExtCtxt<'_>,
span: Span,
tts: TokenStream,
) -> MacroExpanderResult<'static> {
ExpandResult::Ready(
match cx.new_parser_from_tts(tts).parse_pat_allow_top_alt(
None,
RecoverComma::Yes,
RecoverColon::Yes,
CommaRecoveryMode::LikelyTuple,
) {
Ok(parsed) => MacEager::pat(cx.pat(span, ast::PatKind::Deref(parsed))),
Err(err) => DummyResult::any(span, err.emit()),
},
)
}
2 changes: 2 additions & 0 deletions compiler/rustc_builtin_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ mod compile_error;
mod concat;
mod concat_bytes;
mod concat_idents;
mod deref_pat;
mod derive;
mod deriving;
mod edition_panic;
Expand Down Expand Up @@ -84,6 +85,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
concat_idents: concat_idents::expand_concat_idents,
const_format_args: format::expand_format_args,
core_panic: edition_panic::expand_panic,
deref_pat: deref_pat::expand_deref_pat,
env: env::expand_env,
file: source_util::expand_file,
format_args: format::expand_format_args,
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,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) => {
Expand All @@ -1030,7 +1030,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) => {
Expand Down Expand Up @@ -1173,6 +1173,9 @@ pub enum PatKind<'hir> {
/// A `box` pattern.
Box(&'hir Pat<'hir>),

/// A `deref` pattern (currently `deref_pat!()` macro-based syntax).
Deref(&'hir Pat<'hir>),

/// A reference pattern (e.g., `&mut (a, b)`).
Ref(&'hir Pat<'hir>, Mutability),

Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, _), ..)
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1808,6 +1808,12 @@ impl<'a> State<'a> {
self.pclose();
}
}
PatKind::Deref(inner) => {
self.word("deref_pat!");
self.popen();
self.print_pat(inner);
self.pclose();
}
PatKind::Ref(inner, mutbl) => {
let is_range_inner = matches!(inner.kind, PatKind::Range(..));
self.word("&");
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}
PatKind::Or(_)
| PatKind::Box(_)
| PatKind::Deref(_)
| PatKind::Ref(..)
| PatKind::Wild
| PatKind::Err(_) => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -762,6 +761,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| PatKind::Binding(..)
| PatKind::Path(..)
| PatKind::Box(..)
| PatKind::Deref(_)
| PatKind::Ref(..)
| PatKind::Lit(..)
| PatKind::Range(..)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1181,7 +1181,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),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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_pat!({subpattern})")
}
PatKind::Constant { value } => write!(f, "{value}"),
PatKind::InlineConstant { def: _, ref subpattern } => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_passes/src/hir_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
Path,
Tuple,
Box,
Deref,
Ref,
Lit,
Range,
Expand Down Expand Up @@ -566,6 +567,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
Path,
Tuple,
Box,
Deref,
Ref,
Lit,
Range,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
PatKind::DerefPattern { .. } => {
// FIXME(deref_patterns): At least detect that `box _` is irrefutable.
fields = vec![];
arity = 0;
ctor = Opaque(OpaqueId::new());
}
PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,7 @@ symbols! {
deref_method,
deref_mut,
deref_mut_method,
deref_pat,
deref_patterns,
deref_target,
derive,
Expand Down
12 changes: 12 additions & 0 deletions library/core/src/macros/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1714,6 +1714,18 @@ pub(crate) mod builtin {
/* compiler built-in */
}

#[cfg(not(bootstrap))]
/// Unstable placeholder for type ascription.
#[rustc_builtin_macro]
#[unstable(
feature = "deref_patterns",
issue = "87121",
reason = "placeholder syntax for deref patterns"
)]
pub macro deref_pat($pat:pat) {
/* compiler built-in */
}

/// Unstable implementation detail of the `rustc` compiler, do not use.
#[rustc_builtin_macro]
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
8 changes: 8 additions & 0 deletions library/core/src/prelude/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,11 @@ pub use crate::macros::builtin::cfg_eval;
reason = "placeholder syntax for type ascription"
)]
pub use crate::macros::builtin::type_ascribe;

#[cfg(not(bootstrap))]
#[unstable(
feature = "deref_patterns",
issue = "87121",
reason = "placeholder syntax for deref patterns"
)]
pub use crate::macros::builtin::deref_pat;
9 changes: 9 additions & 0 deletions library/std/src/prelude/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ pub use core::prelude::v1::cfg_eval;
)]
pub use core::prelude::v1::type_ascribe;

#[cfg(not(bootstrap))]
// Do not `doc(no_inline)` either.
#[unstable(
feature = "deref_patterns",
issue = "87121",
reason = "placeholder syntax for deref patterns"
)]
pub use core::prelude::v1::deref_pat;

// The file so far is equivalent to core/src/prelude/v1.rs. It is duplicated
// rather than glob imported because we want docs to show these re-exports as
// pointing to within `std`.
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/pattern/deref-patterns/typeck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ use std::rc::Rc;
fn main() {
let vec: Vec<u32> = Vec::new();
match vec {
box [..] => {}
deref_pat!([..]) => {}
_ => {}
}
match Box::new(true) {
box true => {}
deref_pat!(true) => {}
_ => {}
}
match &Box::new(true) {
box true => {}
deref_pat!(true) => {}
_ => {}
}
match &Rc::new(0) {
box (1..) => {}
deref_pat!(1..) => {}
_ => {}
}
// FIXME(deref_patterns): fails to typecheck because `"foo"` has type &str but deref creates a
Expand Down

0 comments on commit 7d50e10

Please sign in to comment.