Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
parse and handle some cases for deref patterns
  • Loading branch information
fee1-dead committed Dec 30, 2023
commit 54bf204083f89582460da213de7e5a369e6a2fdc
5 changes: 4 additions & 1 deletion compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ 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::Ref(s, _) | PatKind::Paren(s) | PatKind::Deref(s) => s.walk(it),

// These patterns do not contain subpatterns, skip.
PatKind::Wild
Expand Down Expand Up @@ -778,6 +778,9 @@ pub enum PatKind {
/// A reference pattern (e.g., `&mut (a, b)`).
Ref(P<Pat>, Mutability),

/// A deref pattern, `k#deref a`.
Deref(P<Pat>),

/// A literal.
Lit(P<Expr>),

Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1271,8 +1271,6 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
vis.visit_path(path);
fields.flat_map_in_place(|field| vis.flat_map_pat_field(field));
}
PatKind::Box(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));
visit_opt(e2, |e| vis.visit_expr(e));
Expand All @@ -1281,7 +1279,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
visit_thin_vec(elems, |elem| vis.visit_pat(elem))
}
PatKind::Paren(inner) => vis.visit_pat(inner),
PatKind::Paren(inner) | PatKind::Box(inner) | PatKind::Ref(inner, _) | PatKind::Deref(inner) => vis.visit_pat(inner),
PatKind::MacCall(mac) => vis.visit_mac_call(mac),
}
vis.visit_span(span);
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_ast/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,13 @@ impl Token {
self.is_keywordable_ident_where(|id| id.name == kw)
}

pub fn is_forced_keyword(&self, kw: Symbol) -> bool {
match self.ident() {
Some((id, IdentKind::Keyword)) => id.name == kw,
_ => false,
}
}

/// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this token is an identifier equal to `kw` ignoring the case.
pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool {
self.is_keyword(kw)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
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::Ref(subpattern, _) | PatKind::Paren(subpattern) | PatKind::Deref(subpattern) => {
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 @@ -94,6 +94,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
PatKind::Ref(inner, mutbl) => {
break hir::PatKind::Ref(self.lower_pat(inner), *mutbl);
}
PatKind::Deref(inner) => {
break hir::PatKind::Deref(self.lower_pat(inner));
}
PatKind::Range(e1, e2, Spanned { node: end, .. }) => {
break hir::PatKind::Range(
e1.as_deref().map(|e| self.lower_expr_within_pat(e, true)),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
}
};
}
gate_all!(forced_keywords, "`k#ident` syntax is experimental",);
gate_all!(forced_keywords, "`k#ident` syntax is experimental");
gate_all!(
if_let_guard,
"`if let` guards are experimental",
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1521,6 +1521,10 @@ impl<'a> State<'a> {
self.pclose();
}
PatKind::MacCall(m) => self.print_mac(m),
PatKind::Deref(inner) => {
self.word("k#deref ");
self.print_pat(inner);
}
}
self.ann.post(self, AnnNode::Pat(pat))
}
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 @@ -1016,7 +1016,7 @@ impl<'hir> Pat<'hir> {
use PatKind::*;
match self.kind {
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true,
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
Box(s) | Ref(s, _) | Binding(.., Some(s)) | Deref(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 @@ -1043,7 +1043,7 @@ impl<'hir> Pat<'hir> {
use PatKind::*;
match self.kind {
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {}
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
Box(s) | Ref(s, _) | Binding(.., Some(s)) | Deref(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 @@ -1189,6 +1189,9 @@ pub enum PatKind<'hir> {
/// A reference pattern (e.g., `&mut (a, b)`).
Ref(&'hir Pat<'hir>, Mutability),

/// A `k#deref` pattern.
Deref(&'hir Pat<'hir>),

/// A literal.
Lit(&'hir Expr<'hir>),

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'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::Ref(ref subpattern, _) | PatKind::Deref(ref subpattern) => {
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 @@ -657,7 +657,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
11 changes: 11 additions & 0 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1805,6 +1805,17 @@ impl<'a> State<'a> {
self.pclose();
}
}
PatKind::Deref(inner) => {
let is_range_inner = matches!(inner.kind, PatKind::Range(..));
self.word("k#deref ");
if is_range_inner {
self.popen();
}
self.print_pat(inner);
if is_range_inner {
self.pclose();
}
}
PatKind::Lit(e) => self.print_expr(e),
PatKind::Range(begin, end, end_kind) => {
if let Some(expr) = begin {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
needs_to_be_read = true;
}
}
PatKind::Or(_) | PatKind::Box(_) | PatKind::Ref(..) | PatKind::Wild => {
PatKind::Or(_) | PatKind::Box(_) | PatKind::Ref(..) | PatKind::Wild | PatKind::Deref(_) => {
// If the PatKind is Or, Box, or Ref, the decision is made later
// as these patterns contains subpatterns
// If the PatKind is Wild, the decision is made based on the other patterns being
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_hir_typeck/src/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
self.cat_pattern_(subplace, subpat, op)?;
}

PatKind::Deref(_) => {
// TODO we can't have a subplace since it will be a temporary
// self.cat_pattern_(subplace, subpat, op)?;
}

PatKind::Slice(before, ref slice, after) => {
let Some(element_ty) = place_with_id.place.ty().builtin_index() else {
debug!("explicit index of non-indexable type {:?}", place_with_id);
Expand Down
18 changes: 17 additions & 1 deletion compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
PatKind::Slice(before, slice, after) => {
self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
}
Expand Down Expand Up @@ -289,7 +290,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| PatKind::Tuple(..)
| PatKind::Box(_)
| PatKind::Range(..)
| PatKind::Slice(..) => AdjustMode::Peel,
| PatKind::Slice(..)
| PatKind::Deref(..) => AdjustMode::Peel,
// A never pattern behaves somewhat like a literal or unit variant.
PatKind::Never => AdjustMode::Peel,
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
Expand Down Expand Up @@ -752,6 +754,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| PatKind::Binding(..)
| PatKind::Path(..)
| PatKind::Box(..)
| PatKind::Deref(..)
| PatKind::Ref(..)
| PatKind::Lit(..)
| PatKind::Range(..) => break 'block None,
Expand Down Expand Up @@ -1970,6 +1973,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
box_ty
}

fn check_pat_deref(
&self,
span: Span,
inner: &'tcx Pat<'tcx>,
expected: Ty<'tcx>,
pat_info: PatInfo<'tcx, '_>,
) -> Ty<'tcx> {
// FIXME(deref_patterns): use `DerefPure` for soundness
let autoderef = self.autoderef(span, expected);
// TODO
todo!()
}

// Precondition: Pat is Ref(inner)
fn check_pat_ref(
&self,
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 @@ -1165,7 +1165,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
11 changes: 10 additions & 1 deletion compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,8 @@ impl<'tcx> Pat<'tcx> {
AscribeUserType { subpattern, .. }
| Binding { subpattern: Some(subpattern), .. }
| Deref { subpattern }
| InlineConstant { subpattern, .. } => subpattern.walk_(it),
| InlineConstant { subpattern, .. }
| DerefPattern { subpattern } => subpattern.walk_(it),
Leaf { subpatterns } | Variant { subpatterns, .. } => {
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
}
Expand Down Expand Up @@ -757,6 +758,11 @@ pub enum PatKind<'tcx> {
subpattern: Box<Pat<'tcx>>,
},

/// `k#deref P`
DerefPattern {
subpattern: Box<Pat<'tcx>>,
},

/// One of the following:
/// * `&str` (represented as a valtree), which will be handled as a string pattern and thus
/// exhaustiveness checking will detect if you use the same string twice in different
Expand Down Expand Up @@ -1182,6 +1188,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
}
write!(f, "{subpattern}")
}
PatKind::DerefPattern { ref subpattern } => {
write!(f, "k#deref {subpattern}")
}
PatKind::Constant { value } => write!(f, "{value}"),
PatKind::InlineConstant { def: _, ref subpattern } => {
write!(f, "{} (from inline const)", subpattern)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/thir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
match &pat.kind {
AscribeUserType { subpattern, ascription: _ }
| Deref { subpattern }
| DerefPattern { subpattern }
| Binding {
subpattern: Some(subpattern),
mutability: _,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
}

hir::PatKind::Deref(subpattern) => {
PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern) }
}

hir::PatKind::Slice(prefix, ref slice, suffix) => {
self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
}
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,11 @@ impl<'a> Parser<'a> {
}
}

fn check_forced_keyword(&mut self, kw: Symbol) -> bool {
self.expected_tokens.push(TokenType::Token(token::Ident(kw, IdentKind::Keyword)));
self.token.is_forced_keyword(kw)
}

/// If the next token is the given keyword, eats it and returns `true`.
/// Otherwise, returns `false`. An expectation is also added for diagnostics purposes.
// Public for rustfmt usage.
Expand All @@ -587,6 +592,15 @@ impl<'a> Parser<'a> {
}
}

pub fn eat_forced_keyword(&mut self, kw: Symbol) -> bool {
if self.check_forced_keyword(kw) {
self.bump();
true
} else {
false
}
}

/// Eats a keyword, optionally ignoring the case.
/// If the case differs (and is ignored) an error is issued.
/// This is useful for recovery.
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_parse/src/parser/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,8 @@ impl<'a> Parser<'a> {
err
});
PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit)))
} else if self.eat_forced_keyword(sym::deref) {
self.parse_pat_deref_patterns()?
} else {
// Try to parse everything else as literal with optional minus
match self.parse_literal_maybe_minus() {
Expand Down Expand Up @@ -965,6 +967,16 @@ impl<'a> Parser<'a> {
}
}

/// Parses `k#deref pat`
fn parse_pat_deref_patterns(&mut self) -> PResult<'a, PatKind> {
// TODO handle standalone `k#deref`s
// let deref_span = self.prev_token.span;
let pat = self.parse_pat_with_range_pat(false, None, None)?;
// TODO
// self.sess.gated_spans.gate(sym::deref_patterns, deref_span.to(self.prev_token.span));
Ok(PatKind::Deref(pat))
}

/// Parses the fields of a struct-like pattern.
fn parse_pat_fields(&mut self) -> PResult<'a, (ThinVec<PatField>, PatFieldsRest)> {
let mut fields = ThinVec::new();
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_passes/src/hir_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
Tuple,
Box,
Ref,
Deref,
Lit,
Range,
Slice
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,10 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
_ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, pat.ty),
};
}
PatKind::DerefPattern { .. } => {
fields = &[];
ctor = Struct;
}
PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
match pat.ty.kind() {
ty::Tuple(fs) => {
Expand Down