Skip to content

Add new PatKind::Missing variants #139035

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 7, 2025
Merged
Changes from all commits
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
8 changes: 7 additions & 1 deletion compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
@@ -563,6 +563,7 @@ impl Pat {
/// This is intended for use by diagnostics.
pub fn to_ty(&self) -> Option<P<Ty>> {
let kind = match &self.kind {
PatKind::Missing => unreachable!(),
// In a type expression `_` is an inference variable.
PatKind::Wild => TyKind::Infer,
// An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`.
@@ -625,7 +626,8 @@ impl Pat {
| PatKind::Guard(s, _) => s.walk(it),

// These patterns do not contain subpatterns, skip.
PatKind::Wild
PatKind::Missing
| PatKind::Wild
| PatKind::Rest
| PatKind::Never
| PatKind::Expr(_)
@@ -676,6 +678,7 @@ impl Pat {
/// Return a name suitable for diagnostics.
pub fn descr(&self) -> Option<String> {
match &self.kind {
PatKind::Missing => unreachable!(),
PatKind::Wild => Some("_".to_string()),
PatKind::Ident(BindingMode::NONE, ident, None) => Some(format!("{ident}")),
PatKind::Ref(pat, mutbl) => pat.descr().map(|d| format!("&{}{d}", mutbl.prefix_str())),
@@ -769,6 +772,9 @@ pub enum RangeSyntax {
// Adding a new variant? Please update `test_pat` in `tests/ui/macros/stringify.rs`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum PatKind {
/// A missing pattern, e.g. for an anonymous param in a bare fn like `fn f(u32)`.
Missing,

/// Represents a wildcard pattern (`_`).
Wild,

2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
@@ -1572,7 +1572,7 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
vis.visit_id(id);
match kind {
PatKind::Err(_guar) => {}
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {}
PatKind::Ident(_binding_mode, ident, sub) => {
vis.visit_ident(ident);
visit_opt(sub, |sub| vis.visit_pat(sub));
2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
@@ -727,7 +727,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
try_visit!(visitor.visit_pat(subpattern));
try_visit!(visitor.visit_expr(guard_condition));
}
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {}
PatKind::Err(_guar) => {}
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
walk_list!(visitor, visit_pat, elems);
11 changes: 3 additions & 8 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1495,18 +1495,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {

fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Option<Ident>] {
self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind {
PatKind::Ident(_, ident, _) => {
if ident.name != kw::Empty {
Some(self.lower_ident(ident))
} else {
None
}
}
PatKind::Missing => None,
PatKind::Ident(_, ident, _) => Some(self.lower_ident(ident)),
PatKind::Wild => Some(Ident::new(kw::Underscore, self.lower_span(param.pat.span))),
_ => {
self.dcx().span_delayed_bug(
param.pat.span,
"non-ident/wild param pat must trigger an error",
"non-missing/ident/wild param pat must trigger an error",
);
None
}
1 change: 1 addition & 0 deletions compiler/rustc_ast_lowering/src/pat.rs
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let pat_hir_id = self.lower_node_id(pattern.id);
let node = loop {
match &pattern.kind {
PatKind::Missing => break hir::PatKind::Missing,
PatKind::Wild => break hir::PatKind::Wild,
PatKind::Never => break hir::PatKind::Never,
PatKind::Ident(binding_mode, ident, sub) => {
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
@@ -239,7 +239,7 @@ impl<'a> AstValidator<'a> {
fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
for Param { pat, .. } in &decl.inputs {
match pat.kind {
PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {}
PatKind::Missing | PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {}
PatKind::Ident(BindingMode::MUT, ident, None) => {
report_err(pat.span, Some(ident), true)
}
11 changes: 3 additions & 8 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
@@ -1622,9 +1622,9 @@ impl<'a> State<'a> {
fn print_pat(&mut self, pat: &ast::Pat) {
self.maybe_print_comment(pat.span.lo());
self.ann.pre(self, AnnNode::Pat(pat));
/* Pat isn't normalized, but the beauty of it
is that it doesn't matter */
/* Pat isn't normalized, but the beauty of it is that it doesn't matter */
match &pat.kind {
PatKind::Missing => unreachable!(),
PatKind::Wild => self.word("_"),
PatKind::Never => self.word("!"),
PatKind::Ident(BindingMode(by_ref, mutbl), ident, sub) => {
@@ -1946,12 +1946,7 @@ impl<'a> State<'a> {
if let Some(eself) = input.to_self() {
self.print_explicit_self(&eself);
} else {
let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
ident.name == kw::Empty
} else {
false
};
if !invalid {
if !matches!(input.pat.kind, PatKind::Missing) {
self.print_pat(&input.pat);
self.word(":");
self.space();
6 changes: 5 additions & 1 deletion compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
@@ -1516,6 +1516,7 @@ impl<'hir> Pat<'hir> {

use PatKind::*;
match self.kind {
Missing => unreachable!(),
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => true,
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it),
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
@@ -1543,7 +1544,7 @@ impl<'hir> Pat<'hir> {

use PatKind::*;
match self.kind {
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => {}
Missing | Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => {}
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(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)),
@@ -1681,6 +1682,9 @@ pub enum TyPatKind<'hir> {

#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum PatKind<'hir> {
/// A missing pattern, e.g. for an anonymous param in a bare fn like `fn f(u32)`.
Missing,

/// Represents a wildcard pattern (i.e., `_`).
Wild,

2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
@@ -744,7 +744,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
visit_opt!(visitor, visit_pat_expr, lower_bound);
visit_opt!(visitor, visit_pat_expr, upper_bound);
}
PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
PatKind::Missing | PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
walk_list!(visitor, visit_pat, prepatterns);
visit_opt!(visitor, visit_pat, slice_pattern);
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/check/region.rs
Original file line number Diff line number Diff line change
@@ -701,6 +701,7 @@ fn resolve_local<'tcx>(

PatKind::Ref(_, _)
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
| PatKind::Missing
| PatKind::Wild
| PatKind::Never
| PatKind::Expr(_)
1 change: 1 addition & 0 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1875,6 +1875,7 @@ impl<'a> State<'a> {
// Pat isn't normalized, but the beauty of it
// is that it doesn't matter
match pat.kind {
PatKind::Missing => unreachable!(),
PatKind::Wild => self.word("_"),
PatKind::Never => self.word("!"),
PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => {
3 changes: 2 additions & 1 deletion compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
@@ -482,7 +482,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

// All of these constitute a read, or match on something that isn't `!`,
// which would require a `NeverToAny` coercion.
hir::PatKind::Binding(_, _, _, _)
hir::PatKind::Missing
| hir::PatKind::Binding(_, _, _, _)
| hir::PatKind::Struct(_, _, _)
| hir::PatKind::TupleStruct(_, _, _)
| hir::PatKind::Tuple(_, _)
2 changes: 2 additions & 0 deletions compiler/rustc_hir_typeck/src/expr_use_visitor.rs
Original file line number Diff line number Diff line change
@@ -611,6 +611,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
for pat in pats {
self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
match &pat.kind {
PatKind::Missing => unreachable!(),
PatKind::Binding(.., opt_sub_pat) => {
// If the opt_sub_pat is None, then the binding does not count as
// a wildcard for the purpose of borrowing discr.
@@ -1884,6 +1885,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
| PatKind::Expr(..)
| PatKind::Range(..)
| PatKind::Never
| PatKind::Missing
| PatKind::Wild
| PatKind::Err(_) => {
// always ok
11 changes: 7 additions & 4 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
@@ -341,7 +341,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};

let ty = match pat.kind {
PatKind::Wild | PatKind::Err(_) => expected,
PatKind::Missing | PatKind::Wild | PatKind::Err(_) => expected,
// We allow any type here; we ensure that the type is uninhabited during match checking.
PatKind::Never => expected,
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
@@ -505,9 +505,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},

// Ref patterns are complicated, we handle them in `check_pat_ref`.
PatKind::Ref(..) => AdjustMode::Pass,
PatKind::Ref(..)
// No need to do anything on a missing pattern.
| PatKind::Missing
// A `_` pattern works with any expected type, so there's no need to do anything.
PatKind::Wild
| PatKind::Wild
// A malformed pattern doesn't have an expected type, so let's just accept any type.
| PatKind::Err(_)
// Bindings also work with whatever the expected type is,
@@ -1037,7 +1039,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| PatKind::Tuple(..)
| PatKind::Slice(..) => "binding",

PatKind::Wild
PatKind::Missing
| PatKind::Wild
| PatKind::Never
| PatKind::Binding(..)
| PatKind::Box(..)
26 changes: 12 additions & 14 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
@@ -778,21 +778,19 @@ impl EarlyLintPass for AnonymousParameters {
}
if let ast::AssocItemKind::Fn(box Fn { ref sig, .. }) = it.kind {
for arg in sig.decl.inputs.iter() {
if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
if ident.name == kw::Empty {
let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
if let ast::PatKind::Missing = arg.pat.kind {
let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);

let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
(snip.as_str(), Applicability::MachineApplicable)
} else {
("<type>", Applicability::HasPlaceholders)
};
cx.emit_span_lint(
ANONYMOUS_PARAMETERS,
arg.pat.span,
BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip },
);
}
let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
(snip.as_str(), Applicability::MachineApplicable)
} else {
("<type>", Applicability::HasPlaceholders)
};
cx.emit_span_lint(
ANONYMOUS_PARAMETERS,
arg.pat.span,
BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip },
);
}
}
}
3 changes: 2 additions & 1 deletion compiler/rustc_lint/src/unused.rs
Original file line number Diff line number Diff line change
@@ -1201,7 +1201,8 @@ impl EarlyLintPass for UnusedParens {
// Do not lint on `(..)` as that will result in the other arms being useless.
Paren(_)
// The other cases do not contain sub-patterns.
| Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {},
| Missing | Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None)
| Path(..) | Err(_) => {},
// These are list-like patterns; parens can always be removed.
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
self.check_unused_parens_pat(cx, p, false, false, keep_space);
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
@@ -747,6 +747,9 @@ pub struct Ascription<'tcx> {

#[derive(Clone, Debug, HashStable, TypeVisitable)]
pub enum PatKind<'tcx> {
/// A missing pattern, e.g. for an anonymous param in a bare fn like `fn f(u32)`.
Missing,

/// A wildcard pattern: `_`.
Wild,

3 changes: 2 additions & 1 deletion compiler/rustc_middle/src/thir/visit.rs
Original file line number Diff line number Diff line change
@@ -250,7 +250,8 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
mut callback: impl FnMut(&'a Pat<'tcx>),
) {
match &pat.kind {
PatKind::Wild
PatKind::Missing
| PatKind::Wild
| PatKind::Binding { subpattern: None, .. }
| PatKind::Constant { value: _ }
| PatKind::Range(_)
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/builder/matches/match_pair.rs
Original file line number Diff line number Diff line change
@@ -118,7 +118,7 @@ impl<'tcx> MatchPairTree<'tcx> {
let place = place_builder.try_to_place(cx);
let mut subpairs = Vec::new();
let test_case = match pattern.kind {
PatKind::Wild | PatKind::Error(_) => None,
PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None,

PatKind::Or { ref pats } => Some(TestCase::Or {
pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
1 change: 1 addition & 0 deletions compiler/rustc_mir_build/src/builder/matches/mod.rs
Original file line number Diff line number Diff line change
@@ -920,6 +920,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {

PatKind::Constant { .. }
| PatKind::Range { .. }
| PatKind::Missing
| PatKind::Wild
| PatKind::Never
| PatKind::Error(_) => {}
1 change: 1 addition & 0 deletions compiler/rustc_mir_build/src/check_unsafety.rs
Original file line number Diff line number Diff line change
@@ -313,6 +313,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
fn visit_pat(&mut self, pat: &'a Pat<'tcx>) {
if self.in_union_destructure {
match pat.kind {
PatKind::Missing => unreachable!(),
// binding to a variable allows getting stuff out of variable
PatKind::Binding { .. }
// match is conditional on having this value
2 changes: 2 additions & 0 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
@@ -290,6 +290,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let mut span = pat.span;

let kind = match pat.kind {
hir::PatKind::Missing => PatKind::Missing,

hir::PatKind::Wild => PatKind::Wild,

hir::PatKind::Never => PatKind::Never,
1 change: 1 addition & 0 deletions compiler/rustc_mir_build/src/thir/print.rs
Original file line number Diff line number Diff line change
@@ -664,6 +664,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
print_indented!(self, "kind: PatKind {", depth_lvl);

match pat_kind {
PatKind::Missing => unreachable!(),
PatKind::Wild => {
print_indented!(self, "Wild", depth_lvl + 1);
}
4 changes: 1 addition & 3 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
@@ -2941,9 +2941,7 @@ impl<'a> Parser<'a> {
}
match ty {
Ok(ty) => {
let ident = Ident::new(kw::Empty, this.prev_token.span);
let bm = BindingMode::NONE;
let pat = this.mk_pat_ident(ty.span, bm, ident);
let pat = this.mk_pat(ty.span, PatKind::Missing);
(pat, ty)
}
// If this is a C-variadic argument and we hit an error, return the error.
2 changes: 2 additions & 0 deletions compiler/rustc_passes/src/input_stats.rs
Original file line number Diff line number Diff line change
@@ -295,6 +295,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
record_variants!(
(self, p, p.kind, Some(p.hir_id), hir, Pat, PatKind),
[
Missing,
Wild,
Binding,
Struct,
@@ -597,6 +598,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
record_variants!(
(self, p, p.kind, None, ast, Pat, PatKind),
[
Missing,
Wild,
Ident,
Struct,
5 changes: 1 addition & 4 deletions compiler/rustc_passes/src/liveness.rs
Original file line number Diff line number Diff line change
@@ -96,7 +96,7 @@ use rustc_middle::query::Providers;
use rustc_middle::span_bug;
use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt};
use rustc_session::lint;
use rustc_span::{BytePos, Span, Symbol, kw, sym};
use rustc_span::{BytePos, Span, Symbol, sym};
use tracing::{debug, instrument};

use self::LiveNodeKind::*;
@@ -1481,9 +1481,6 @@ impl<'tcx> Liveness<'_, 'tcx> {

fn should_warn(&self, var: Variable) -> Option<String> {
let name = self.ir.variable_name(var);
if name == kw::Empty {
return None;
}
let name = name.as_str();
if name.as_bytes()[0] == b'_' {
return None;
2 changes: 1 addition & 1 deletion compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
@@ -457,7 +457,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
PatKind::AscribeUserType { subpattern, .. }
| PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern),
PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
PatKind::Missing | PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
ctor = Wildcard;
fields = vec![];
arity = 0;
Loading