Auto merge of #134248 - oli-obk:patkind-path-removal, r=BoxyUwU

Merge `PatKind::Path` into `PatKind::Expr`

Follow-up to #134228

We always had a duplication where `Path`s could be represented as `PatKind::Path` or `PatKind::Lit(ExprKind::Path)`. We had to handle both everywhere, and still do after #134228, so I'm removing it now.
This commit is contained in:
bors 2025-01-29 19:16:29 +00:00
commit ae5de6c759
42 changed files with 299 additions and 183 deletions

View file

@ -1391,7 +1391,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
None,
);
// Destructure like a unit struct.
let unit_struct_pat = hir::PatKind::Path(qpath);
let unit_struct_pat = hir::PatKind::Expr(self.arena.alloc(hir::PatExpr {
kind: hir::PatExprKind::Path(qpath),
hir_id: self.next_id(),
span: self.lower_span(lhs.span),
}));
return self.pat_without_dbm(lhs.span, unit_struct_pat);
}
}

View file

@ -69,7 +69,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
break hir::PatKind::Path(qpath);
let kind = hir::PatExprKind::Path(qpath);
let span = self.lower_span(pattern.span);
let expr = hir::PatExpr { hir_id: pat_hir_id, span, kind };
let expr = self.arena.alloc(expr);
return hir::Pat {
hir_id: self.next_id(),
kind: hir::PatKind::Expr(expr),
span,
default_binding_modes: true,
};
}
PatKind::Struct(qself, path, fields, etc) => {
let qpath = self.lower_qpath(
@ -304,16 +313,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)
}
Some(res) => {
let hir_id = self.next_id();
let res = self.lower_res(res);
hir::PatKind::Path(hir::QPath::Resolved(
None,
self.arena.alloc(hir::Path {
span: self.lower_span(ident.span),
res,
segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
}),
))
let span = self.lower_span(ident.span);
hir::PatKind::Expr(self.arena.alloc(hir::PatExpr {
kind: hir::PatExprKind::Path(hir::QPath::Resolved(
None,
self.arena.alloc(hir::Path {
span,
res,
segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), self.next_id(), res)],
}),
)),
hir_id: self.next_id(),
span,
}))
}
}
}

View file

@ -1437,7 +1437,7 @@ impl<'hir> Pat<'hir> {
use PatKind::*;
match self.kind {
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
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)),
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
@ -1464,7 +1464,7 @@ impl<'hir> Pat<'hir> {
use PatKind::*;
match self.kind {
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
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)),
@ -1618,9 +1618,6 @@ pub enum PatKind<'hir> {
/// A never pattern `!`.
Never,
/// A path pattern for a unit struct/variant or a (maybe-associated) constant.
Path(QPath<'hir>),
/// A tuple pattern (e.g., `(a, b)`).
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
/// `0 <= position <= subpats.len()`

View file

@ -709,9 +709,6 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span));
walk_list!(visitor, visit_pat, children);
}
PatKind::Path(ref qpath) => {
try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span));
}
PatKind::Struct(ref qpath, fields, _) => {
try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span));
walk_list!(visitor, visit_pat_field, fields);

View file

@ -105,7 +105,10 @@ impl hir::Pat<'_> {
let mut variants = vec![];
self.walk(|p| match &p.kind {
PatKind::Or(_) => false,
PatKind::Path(hir::QPath::Resolved(_, path))
PatKind::Expr(hir::PatExpr {
kind: hir::PatExprKind::Path(hir::QPath::Resolved(_, path)),
..
})
| PatKind::TupleStruct(hir::QPath::Resolved(_, path), ..)
| PatKind::Struct(hir::QPath::Resolved(_, path), ..) => {
if let Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), id) =

View file

@ -703,7 +703,6 @@ fn resolve_local<'tcx>(
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
| PatKind::Wild
| PatKind::Never
| PatKind::Path(_)
| PatKind::Expr(_)
| PatKind::Range(_, _, _)
| PatKind::Err(_) => false,

View file

@ -41,8 +41,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)),
..
})
| hir::Node::Pat(hir::Pat {
kind: hir::PatKind::Path(hir::QPath::TypeRelative(qself, _)),
| hir::Node::PatExpr(hir::PatExpr {
kind: hir::PatExprKind::Path(hir::QPath::TypeRelative(qself, _)),
..
}) if qself.hir_id == self_ty.hir_id => true,
_ => false,

View file

@ -1906,9 +1906,6 @@ impl<'a> State<'a> {
}
self.pclose();
}
PatKind::Path(ref qpath) => {
self.print_qpath(qpath, true);
}
PatKind::Struct(ref qpath, fields, etc) => {
self.print_qpath(qpath, true);
self.nbsp();

View file

@ -480,7 +480,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir::PatKind::Binding(_, _, _, _)
| hir::PatKind::Struct(_, _, _)
| hir::PatKind::TupleStruct(_, _, _)
| hir::PatKind::Path(_)
| hir::PatKind::Tuple(_, _)
| hir::PatKind::Box(_)
| hir::PatKind::Ref(_, _)

View file

@ -11,10 +11,9 @@ use hir::def::DefKind;
use hir::pat_util::EnumerateAndAdjustIterator as _;
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, Res};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::{HirId, PatKind};
use rustc_hir::{self as hir, HirId, PatExpr, PatExprKind, PatKind};
use rustc_lint::LateContext;
use rustc_middle::hir::place::ProjectionKind;
// Export these here so that Clippy can use them.
@ -564,11 +563,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
// FIXME(never_patterns): does this do what I expect?
needs_to_be_read = true;
}
PatKind::Path(qpath) => {
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
// A `Path` pattern is just a name like `Foo`. This is either a
// named constant or else it refers to an ADT variant
let res = self.cx.typeck_results().qpath_res(qpath, pat.hir_id);
let res = self.cx.typeck_results().qpath_res(qpath, *hir_id);
match res {
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
// Named constants have to be equated with the value
@ -581,7 +580,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
// Otherwise, this is a struct/enum variant, and so it's
// only a read if we need to read the discriminant.
needs_to_be_read |=
self.is_multivariant_adt(place.place.ty(), pat.span);
self.is_multivariant_adt(place.place.ty(), *span);
}
}
}
@ -1801,8 +1800,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
}
}
PatKind::Path(_)
| PatKind::Binding(.., None)
PatKind::Binding(.., None)
| PatKind::Expr(..)
| PatKind::Range(..)
| PatKind::Never

View file

@ -5,12 +5,12 @@ use hir::def_id::LocalDefId;
use rustc_ast::util::parser::ExprPrecedence;
use rustc_data_structures::packed::Pu128;
use rustc_errors::{Applicability, Diag, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId,
Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicateKind, expr_needs_parens,
self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind,
GenericBound, HirId, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, TyKind,
WherePredicateKind, expr_needs_parens,
};
use rustc_hir_analysis::collect::suggest_impl_trait;
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
@ -1422,8 +1422,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// since the user probably just misunderstood how `let else`
// and `&&` work together.
if let Some((_, hir::Node::LetStmt(local))) = cond_parent
&& let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) =
&local.pat.kind
&& let hir::PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
| hir::PatKind::TupleStruct(qpath, _, _) = &local.pat.kind
&& let hir::QPath::Resolved(None, path) = qpath
&& let Some(did) = path
.res

View file

@ -177,8 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
})
| hir::Node::Pat(&hir::Pat {
kind:
hir::PatKind::Path(QPath::TypeRelative(rcvr, segment))
| hir::PatKind::Struct(QPath::TypeRelative(rcvr, segment), ..)
hir::PatKind::Struct(QPath::TypeRelative(rcvr, segment), ..)
| hir::PatKind::TupleStruct(QPath::TypeRelative(rcvr, segment), ..),
span,
..

View file

@ -11,8 +11,8 @@ use rustc_errors::{
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::{
self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatKind,
expr_needs_parens,
self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatExpr,
PatExprKind, PatKind, expr_needs_parens,
};
use rustc_infer::infer;
use rustc_middle::traits::PatternOriginExpr;
@ -312,9 +312,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'_, 'tcx>) {
let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info;
let path_res = match &pat.kind {
PatKind::Path(qpath) => {
Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span))
let path_res = match pat.kind {
PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref qpath), hir_id, span }) => {
Some(self.resolve_ty_and_res_fully_qualified_call(qpath, *hir_id, *span))
}
_ => None,
};
@ -333,6 +333,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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(ref qpath), hir_id, span }) => {
let ty = self.check_pat_path(
*hir_id,
pat.hir_id,
*span,
qpath,
path_res.unwrap(),
expected,
ti,
);
self.write_ty(*hir_id, ty);
ty
}
PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
PatKind::Binding(ba, var_id, ident, sub) => {
@ -341,9 +354,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
}
PatKind::Path(ref qpath) => {
self.check_pat_path(pat.hir_id, pat.span, qpath, path_res.unwrap(), expected, ti)
}
PatKind::Struct(ref qpath, fields, has_rest_pat) => {
self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
}
@ -456,16 +466,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| PatKind::Slice(..) => 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.
// All other literals result in non-reference types.
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`.
//
// Call `resolve_vars_if_possible` here for inline const blocks.
PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
ty::Ref(..) => AdjustMode::Pass,
_ => AdjustMode::Peel,
},
PatKind::Path(_) => match opt_path_res.unwrap() {
PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => match opt_path_res.unwrap() {
// These constants can be of a reference type, e.g. `const X: &u8 = &0;`.
// Peeling the reference types too early will cause type checking failures.
// Although it would be possible to *also* peel the types of the constants too.
@ -476,6 +477,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// a reference type wherefore peeling doesn't give up any expressiveness.
_ => AdjustMode::Peel,
},
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
// All other literals result in non-reference types.
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`.
//
// Call `resolve_vars_if_possible` here for inline const blocks.
PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
ty::Ref(..) => AdjustMode::Pass,
_ => AdjustMode::Peel,
},
// Ref patterns are complicated, we handle them in `check_pat_ref`.
PatKind::Ref(..) => AdjustMode::Pass,
// A `_` pattern works with any expected type, so there's no need to do anything.
@ -1001,7 +1013,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
PatKind::Wild
| PatKind::Never
| PatKind::Binding(..)
| PatKind::Path(..)
| PatKind::Box(..)
| PatKind::Deref(_)
| PatKind::Ref(..)
@ -1139,7 +1150,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn check_pat_path(
&self,
hir_id: HirId,
path_id: HirId,
pat_id_for_diag: HirId,
span: Span,
qpath: &hir::QPath<'_>,
path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
@ -1193,11 +1205,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Type-check the path.
let (pat_ty, pat_res) =
self.instantiate_value_path(segments, opt_ty, res, span, span, hir_id);
self.instantiate_value_path(segments, opt_ty, res, span, span, path_id);
if let Err(err) =
self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, pat_ty)
{
self.emit_bad_pat_path(err, hir_id, span, res, pat_res, pat_ty, segments);
self.emit_bad_pat_path(err, pat_id_for_diag, span, res, pat_res, pat_ty, segments);
}
pat_ty
}

View file

@ -6,7 +6,7 @@ use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::{
AmbigArg, BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat,
PatKind, Path, PathSegment, QPath, Ty, TyKind,
PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Ty, TyKind,
};
use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -164,11 +164,9 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
TyKind::Path(QPath::Resolved(_, path)) => {
if lint_ty_kind_usage(cx, &path.res) {
let span = match cx.tcx.parent_hir_node(ty.hir_id) {
Node::Pat(Pat {
kind:
PatKind::Path(qpath)
| PatKind::TupleStruct(qpath, ..)
| PatKind::Struct(qpath, ..),
Node::PatExpr(PatExpr { kind: PatExprKind::Path(qpath), .. })
| Node::Pat(Pat {
kind: PatKind::TupleStruct(qpath, ..) | PatKind::Struct(qpath, ..),
..
})
| Node::Expr(

View file

@ -1,7 +1,7 @@
use rustc_abi::ExternAbi;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::FnKind;
use rustc_hir::{AttrArgs, AttrItem, AttrKind, GenericParamKind, PatKind};
use rustc_hir::{AttrArgs, AttrItem, AttrKind, GenericParamKind, PatExprKind, PatKind};
use rustc_middle::ty;
use rustc_session::config::CrateType;
use rustc_session::{declare_lint, declare_lint_pass};
@ -527,7 +527,11 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) {
// Lint for constants that look like binding identifiers (#7526)
if let PatKind::Path(hir::QPath::Resolved(None, path)) = p.kind {
if let PatKind::Expr(hir::PatExpr {
kind: PatExprKind::Path(hir::QPath::Resolved(None, path)),
..
}) = p.kind
{
if let Res::Def(DefKind::Const, _) = path.res {
if let [segment] = path.segments {
NonUpperCaseGlobals::check_upper_case(

View file

@ -332,10 +332,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
.unwrap_or_else(PatKind::Error)
}
hir::PatKind::Path(ref qpath) => {
return self.lower_path(qpath, pat.hir_id, pat.span);
}
hir::PatKind::Deref(subpattern) => {
let mutable = self.typeck_results.pat_has_ref_mut_binding(subpattern);
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };

View file

@ -10,11 +10,10 @@ use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
use rustc_abi::FieldIdx;
use rustc_data_structures::unord::UnordSet;
use rustc_errors::MultiSpan;
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Node, PatKind, TyKind};
use rustc_hir::{self as hir, Node, PatKind, TyKind};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::privacy::Level;
use rustc_middle::query::Providers;
@ -637,10 +636,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
let res = self.typeck_results().qpath_res(path, pat.hir_id);
self.handle_field_pattern_match(pat, res, fields);
}
PatKind::Path(ref qpath) => {
let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
self.handle_res(res);
}
PatKind::TupleStruct(ref qpath, fields, dotdot) => {
let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
self.handle_tuple_field_pattern_match(pat, res, fields, dotdot);
@ -652,6 +647,17 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
self.in_pat = false;
}
fn visit_pat_expr(&mut self, expr: &'tcx rustc_hir::PatExpr<'tcx>) {
match &expr.kind {
rustc_hir::PatExprKind::Path(qpath) => {
let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
self.handle_res(res);
}
_ => {}
}
intravisit::walk_pat_expr(self, expr);
}
fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
self.handle_res(path.res);
intravisit::walk_path(self, path);

View file

@ -298,7 +298,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
TupleStruct,
Or,
Never,
Path,
Tuple,
Box,
Deref,

View file

@ -303,7 +303,8 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
return kw::Underscore;
}
PatKind::Binding(_, _, ident, _) => return ident.name,
PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
PatKind::TupleStruct(ref p, ..)
| PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref p), .. }) => qpath_to_string(p),
PatKind::Or(pats) => {
pats.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(" | ")
}

View file

@ -4,7 +4,9 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatKind, QPath};
use rustc_hir::{
ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatExpr, PatExprKind, PatKind, QPath,
};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::TyCtxt;
use rustc_span::hygiene::MacroKind;
@ -191,17 +193,21 @@ impl SpanMapVisitor<'_> {
}
fn handle_pat(&mut self, p: &Pat<'_>) {
let mut check_qpath = |qpath, hir_id| match qpath {
QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => {
self.infer_id(path.hir_id, Some(hir_id), qpath.span());
}
QPath::Resolved(_, path) => self.handle_path(path),
_ => {}
};
match p.kind {
PatKind::Binding(_, _, _, Some(p)) => self.handle_pat(p),
PatKind::Struct(qpath, _, _)
| PatKind::TupleStruct(qpath, _, _)
| PatKind::Path(qpath) => match qpath {
QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => {
self.infer_id(path.hir_id, Some(p.hir_id), qpath.span());
}
QPath::Resolved(_, path) => self.handle_path(path),
_ => {}
},
PatKind::Struct(qpath, _, _) | PatKind::TupleStruct(qpath, _, _) => {
check_qpath(qpath, p.hir_id)
}
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, .. }) => {
check_qpath(*qpath, *hir_id)
}
PatKind::Or(pats) => {
for pat in pats {
self.handle_pat(pat);

View file

@ -56,7 +56,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x),
PatKind::Path(_) | PatKind::Expr(_) => true,
PatKind::Expr(_) => true,
}
}

View file

@ -7,7 +7,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_lint_allowed, is_never_expr, msrvs, pat_and_expr_can_be_question_mark, peel_blocks};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::lint::in_external_macro;
@ -292,7 +292,12 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: boo
// Only do the check if the type is "spelled out" in the pattern
if !matches!(
pat.kind,
PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..)
PatKind::Struct(..)
| PatKind::TupleStruct(..)
| PatKind::Expr(PatExpr {
kind: PatExprKind::Path(..),
..
},)
) {
return;
}

View file

@ -1,6 +1,6 @@
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath};
use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::GenericArgKind;
use rustc_session::declare_lint_pass;
@ -68,7 +68,7 @@ fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<HirId> {
}
fn get_none<'tcx>(cx: &LateContext<'tcx>, arm: &Arm<'tcx>) -> Option<&'tcx Expr<'tcx>> {
if let PatKind::Path(QPath::Resolved(_, path)) = arm.pat.kind
if let PatKind::Expr(PatExpr { kind: PatExprKind::Path(QPath::Resolved(_, path)), .. }) = arm.pat.kind
&& let Some(def_id) = path.res.opt_def_id()
// Since it comes from a pattern binding, we need to get the parent to actually match
// against it.

View file

@ -8,7 +8,7 @@ use clippy_utils::{
};
use rustc_errors::MultiSpan;
use rustc_hir::LangItem::OptionNone;
use rustc_hir::{Arm, Expr, HirId, Pat, PatKind};
use rustc_hir::{Arm, Expr, HirId, Pat, PatExpr, PatExprKind, PatKind};
use rustc_lint::LateContext;
use rustc_span::Span;
@ -119,7 +119,11 @@ fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
}
match arm.pat.kind {
PatKind::Binding(..) | PatKind::Wild => true,
PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
PatKind::Expr(PatExpr {
kind: PatExprKind::Path(qpath),
hir_id,
..
}) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
_ => false,
}
}

View file

@ -6,7 +6,7 @@ use rustc_ast::BindingMode;
use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Arm, Expr, ExprKind, Pat, PatKind, Path, QPath};
use rustc_hir::{Arm, Expr, ExprKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::Ty;
use rustc_span::symbol::Ident;
@ -60,7 +60,16 @@ pub(crate) fn check_match(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Exp
/// accepted.
fn is_variant_or_wildcard(cx: &LateContext<'_>, pat: &Pat<'_>, can_be_wild: bool, must_match_err: bool) -> bool {
match pat.kind {
PatKind::Wild | PatKind::Path(..) | PatKind::Binding(_, _, _, None) if can_be_wild => true,
PatKind::Wild
| PatKind::Expr(PatExpr {
kind: PatExprKind::Path(_),
..
})
| PatKind::Binding(_, _, _, None)
if can_be_wild =>
{
true
},
PatKind::TupleStruct(qpath, ..) => {
is_res_lang_ctor(cx, cx.qpath_res(&qpath, pat.hir_id), ResultErr) == must_match_err
},

View file

@ -7,7 +7,7 @@ use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg};
use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionNone, ResultErr};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Arm, Expr, Pat, PatKind};
use rustc_hir::{Arm, Expr, Pat, PatExpr, PatExprKind, PatKind};
use rustc_lint::LateContext;
use rustc_middle::ty::Ty;
use rustc_span::sym;
@ -89,7 +89,11 @@ fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<(&
if arms.len() == 2
&& arms.iter().all(|arm| arm.guard.is_none())
&& let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| match arm.pat.kind {
PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
PatKind::Expr(PatExpr {
hir_id,
kind: PatExprKind::Path(qpath),
..
}) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
PatKind::TupleStruct(ref qpath, [pat], _) => {
matches!(pat.kind, PatKind::Wild)
&& is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr)

View file

@ -11,7 +11,7 @@ use rustc_ast::util::parser::ExprPrecedence;
use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_hir::def::Res;
use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath};
use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Mutability, Pat, PatExpr, PatExprKind, PatKind, Path, QPath};
use rustc_lint::LateContext;
use rustc_span::{SyntaxContext, sym};
@ -256,9 +256,11 @@ pub(super) fn try_parse_pattern<'tcx>(
match pat.kind {
PatKind::Wild => Some(OptionPat::Wild),
PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionNone) => {
Some(OptionPat::None)
},
PatKind::Expr(PatExpr {
kind: PatExprKind::Path(qpath),
hir_id,
..
}) if is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone) => Some(OptionPat::None),
PatKind::TupleStruct(ref qpath, [pattern], _)
if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionSome) && pat.span.ctxt() == ctxt =>
{

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks};
use rustc_errors::Applicability;
use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath};
use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, LangItem, Mutability, PatExpr, PatExprKind, PatKind, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty;
@ -59,7 +59,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
matches!(
arm.pat.kind,
PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionNone)
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. }) if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionNone)
)
}

View file

@ -7,7 +7,7 @@ use rustc_arena::DroplessArena;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExprKind, PatKind, RangeEnd};
use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExpr, PatExprKind, PatKind, RangeEnd};
use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty;
@ -292,7 +292,11 @@ impl<'a> NormalizedPat<'a> {
Self::Tuple(var_id, pats)
},
PatKind::Or(pats) => Self::Or(arena.alloc_from_iter(pats.iter().map(|pat| Self::from_pat(cx, arena, pat)))),
PatKind::Path(ref path) => Self::Path(cx.qpath_res(path, pat.hir_id).opt_def_id()),
PatKind::Expr(PatExpr {
kind: PatExprKind::Path(path),
hir_id,
..
}) => Self::Path(cx.qpath_res(path, *hir_id).opt_def_id()),
PatKind::Tuple(pats, wild_idx) => {
let field_count = match cx.typeck_results().pat_ty(pat).kind() {
ty::Tuple(subs) => subs.len(),

View file

@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns};
use rustc_errors::Applicability;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::{Arm, Expr, PatKind, PathSegment, QPath, Ty, TyKind};
use rustc_hir::{Arm, Expr, PatExpr, PatExprKind, PatKind, PathSegment, QPath, Ty, TyKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, VariantDef};
use rustc_span::sym;
@ -60,8 +60,13 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
// covered by the set of guards that cover it, but that's really hard to do.
recurse_or_patterns(arm.pat, |pat| {
let path = match &peel_hir_pat_refs(pat).0.kind {
PatKind::Path(path) => {
let id = match cx.qpath_res(path, pat.hir_id) {
PatKind::Expr(PatExpr {
hir_id,
kind: PatExprKind::Path(path),
..
}) => {
// FIXME(clippy): don't you want to use the hir id of the peeled pat?
let id = match cx.qpath_res(path, *hir_id) {
Res::Def(
DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,
_,

View file

@ -8,7 +8,9 @@ use clippy_utils::{
};
use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone;
use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatExprKind, PatKind, Path, QPath};
use rustc_hir::{
Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatExpr, PatExprKind, PatKind, Path, QPath,
};
use rustc_lint::LateContext;
use rustc_span::sym;
@ -183,7 +185,13 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
return !matches!(annot, BindingMode(ByRef::Yes(_), _)) && pat_ident.name == first_seg.ident.name;
},
// Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
(PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => {
(
PatKind::Expr(PatExpr {
kind: PatExprKind::Path(QPath::Resolved(_, p_path)),
..
}),
ExprKind::Path(QPath::Resolved(_, e_path)),
) => {
return over(p_path.segments, e_path.segments, |p_seg, e_seg| {
p_seg.ident.name == e_seg.ident.name
});

View file

@ -9,7 +9,7 @@ use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExprKind, PatKind, QPath, UnOp};
use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExpr, PatExprKind, PatKind, QPath, UnOp};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, GenericArgKind, Ty};
use rustc_span::{Span, Symbol, sym};
@ -149,8 +149,12 @@ fn find_method_and_type<'tcx>(
None
}
},
PatKind::Path(ref path) => {
if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(path, check_pat.hir_id)
PatKind::Expr(PatExpr {
kind: PatExprKind::Path(path),
hir_id,
..
}) => {
if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(path, *hir_id)
&& let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
{
let method = if cx.tcx.lang_items().option_none_variant() == Some(variant_id) {
@ -351,10 +355,20 @@ fn found_good_method<'tcx>(
None
}
},
(PatKind::TupleStruct(path_left, patterns, _), PatKind::Path(path_right))
| (PatKind::Path(path_left), PatKind::TupleStruct(path_right, patterns, _))
if patterns.len() == 1 =>
{
(
PatKind::TupleStruct(path_left, patterns, _),
PatKind::Expr(PatExpr {
kind: PatExprKind::Path(path_right),
..
}),
)
| (
PatKind::Expr(PatExpr {
kind: PatExprKind::Path(path_left),
..
}),
PatKind::TupleStruct(path_right, patterns, _),
) if patterns.len() == 1 => {
if let PatKind::Wild = patterns[0].kind {
find_good_method_for_match(
cx,
@ -389,7 +403,13 @@ fn found_good_method<'tcx>(
None
}
},
(PatKind::Path(path_left), PatKind::Wild) => get_good_method(cx, arms, path_left),
(
PatKind::Expr(PatExpr {
kind: PatExprKind::Path(path_left),
..
}),
PatKind::Wild,
) => get_good_method(cx, arms, path_left),
_ => None,
}
}

View file

@ -114,7 +114,7 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
}
let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat);
let (msg, sugg) = if let PatKind::Path(_) | PatKind::Expr(_) = pat.kind
let (msg, sugg) = if let PatKind::Expr(_) = pat.kind
&& let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex))
&& let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
&& let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
@ -331,14 +331,16 @@ impl<'a> PatState<'a> {
#[expect(clippy::similar_names)]
fn add_pat<'tcx>(&mut self, cx: &'a PatCtxt<'tcx>, pat: &'tcx Pat<'_>) -> bool {
match pat.kind {
PatKind::Path(_)
if match *cx.typeck.pat_ty(pat).peel_refs().kind() {
ty::Adt(adt, _) => adt.is_enum() || (adt.is_struct() && !adt.non_enum_variant().fields.is_empty()),
ty::Tuple(tys) => !tys.is_empty(),
ty::Array(_, len) => len.try_to_target_usize(cx.tcx) != Some(1),
ty::Slice(..) => true,
_ => false,
} =>
PatKind::Expr(PatExpr {
kind: PatExprKind::Path(_),
..
}) if match *cx.typeck.pat_ty(pat).peel_refs().kind() {
ty::Adt(adt, _) => adt.is_enum() || (adt.is_struct() && !adt.non_enum_variant().fields.is_empty()),
ty::Tuple(tys) => !tys.is_empty(),
ty::Array(_, len) => len.try_to_target_usize(cx.tcx) != Some(1),
ty::Slice(..) => true,
_ => false,
} =>
{
matches!(self, Self::Wild)
},
@ -386,7 +388,6 @@ impl<'a> PatState<'a> {
| PatKind::Binding(_, _, _, None)
| PatKind::Expr(_)
| PatKind::Range(..)
| PatKind::Path(_)
| PatKind::Never
| PatKind::Err(_) => {
*self = PatState::Wild;

View file

@ -7,7 +7,9 @@ use clippy_utils::{
use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
use rustc_hir::def::Res;
use rustc_hir::{Arm, BindingMode, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp};
use rustc_hir::{
Arm, BindingMode, Expr, ExprKind, MatchSource, Mutability, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, UnOp,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::SyntaxContext;
@ -281,7 +283,11 @@ fn try_convert_match<'tcx>(
fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
match arm.pat.kind {
PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
PatKind::Expr(PatExpr {
kind: PatExprKind::Path(qpath),
hir_id,
..
}) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
PatKind::TupleStruct(ref qpath, [first_pat], _) => {
is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr)
&& matches!(first_pat.kind, PatKind::Wild)

View file

@ -10,7 +10,7 @@ use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
use rustc_hir::{
self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind,
HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind,
HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind,
};
use rustc_hir_analysis::lower_ty;
use rustc_lint::{LateContext, LateLintPass};
@ -258,7 +258,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
&& self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS)
&& let Some(&StackItem::Check { impl_id, .. }) = self.stack.last()
// get the path from the pattern
&& let PatKind::Path(QPath::Resolved(_, path))
&& let PatKind::Expr(&PatExpr { kind: PatExprKind::Path(QPath::Resolved(_, path)), .. })
| PatKind::TupleStruct(QPath::Resolved(_, path), _, _)
| PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind
&& cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id).instantiate_identity()

View file

@ -708,11 +708,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
self.qpath(qpath);
self.slice(fields, |pat| self.pat(pat));
},
PatKind::Path(ref qpath) => {
bind!(self, qpath);
kind!("Path(ref {qpath})");
self.qpath(qpath);
},
PatKind::Tuple(fields, skip_pos) => {
bind!(self, fields);
kind!("Tuple({fields}, {skip_pos:?})");

View file

@ -524,7 +524,6 @@ impl HirEqInterExpr<'_, '_, '_> {
}
eq
},
(PatKind::Path(l), PatKind::Path(r)) => self.eq_qpath(l, r),
(&PatKind::Expr(l), &PatKind::Expr(r)) => self.eq_pat_expr(l, r),
(&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
(&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
@ -1120,7 +1119,6 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
self.hash_pat(pat);
}
},
PatKind::Path(ref qpath) => self.hash_qpath(qpath),
PatKind::Range(s, e, i) => {
if let Some(s) = s {
self.hash_pat_expr(s);

View file

@ -106,8 +106,8 @@ use rustc_hir::{
self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext,
Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind,
ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat,
PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef,
TyKind, UnOp, def,
PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
TraitItemRef, TraitRef, TyKind, UnOp, def,
};
use rustc_lexer::{TokenKind, tokenize};
use rustc_lint::{LateContext, Level, Lint, LintContext};
@ -560,7 +560,20 @@ macro_rules! maybe_path {
};
}
maybe_path!(Expr, ExprKind);
maybe_path!(Pat, PatKind);
impl<'hir> MaybePath<'hir> for Pat<'hir> {
fn hir_id(&self) -> HirId {
self.hir_id
}
fn qpath_opt(&self) -> Option<&QPath<'hir>> {
match &self.kind {
PatKind::Expr(PatExpr {
kind: PatExprKind::Path(qpath),
..
}) => Some(qpath),
_ => None,
}
}
}
maybe_path!(Ty, TyKind);
/// If `maybe_path` is a path node, resolves it, otherwise returns `Res::Err`
@ -1753,7 +1766,11 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.
PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)),
PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
PatKind::Expr(PatExpr {
kind: PatExprKind::Path(qpath),
hir_id,
..
}) => is_enum_variant(cx, qpath, *hir_id),
PatKind::Or(pats) => {
// TODO: should be the honest check, that pats is exhaustive set
are_refutable(cx, pats)

View file

@ -29,6 +29,7 @@ const used_const: isize = 0;
pub const used_const2: isize = used_const;
const USED_CONST: isize = 1;
const CONST_USED_IN_ENUM_DISCRIMINANT: isize = 11;
const CONST_USED_IN_RANGE_PATTERN: isize = 12;
pub type typ = *const UsedStruct4;
pub struct PubStruct;
@ -81,6 +82,7 @@ pub fn pub_fn() {
match i {
USED_STATIC => (),
USED_CONST => (),
CONST_USED_IN_RANGE_PATTERN..100 => {}
_ => ()
}
f::<StructUsedInGeneric>();

View file

@ -17,19 +17,19 @@ LL | const priv_const: isize = 0;
| ^^^^^^^^^^
error: struct `PrivStruct` is never constructed
--> $DIR/lint-dead-code-1.rs:35:8
--> $DIR/lint-dead-code-1.rs:36:8
|
LL | struct PrivStruct;
| ^^^^^^^^^^
error: enum `priv_enum` is never used
--> $DIR/lint-dead-code-1.rs:64:6
--> $DIR/lint-dead-code-1.rs:65:6
|
LL | enum priv_enum { foo2, bar2 }
| ^^^^^^^^^
error: variant `bar3` is never constructed
--> $DIR/lint-dead-code-1.rs:67:5
--> $DIR/lint-dead-code-1.rs:68:5
|
LL | enum used_enum {
| --------- variant in this enum
@ -38,25 +38,25 @@ LL | bar3
| ^^^^
error: function `priv_fn` is never used
--> $DIR/lint-dead-code-1.rs:88:4
--> $DIR/lint-dead-code-1.rs:90:4
|
LL | fn priv_fn() {
| ^^^^^^^
error: function `foo` is never used
--> $DIR/lint-dead-code-1.rs:93:4
--> $DIR/lint-dead-code-1.rs:95:4
|
LL | fn foo() {
| ^^^
error: function `bar` is never used
--> $DIR/lint-dead-code-1.rs:98:4
--> $DIR/lint-dead-code-1.rs:100:4
|
LL | fn bar() {
| ^^^
error: function `baz` is never used
--> $DIR/lint-dead-code-1.rs:102:4
--> $DIR/lint-dead-code-1.rs:104:4
|
LL | fn baz() -> impl Copy {
| ^^^

View file

@ -1,5 +1,7 @@
//@ run-pass
#![deny(dead_code)]
#[derive(PartialEq, Eq)]
pub enum Foo {
FooA(()),
@ -11,6 +13,7 @@ impl Foo {
const A2: Foo = Self::FooA(());
const A3: Self = Foo::FooA(());
const A4: Self = Self::FooA(());
const A5: u32 = 1;
}
fn main() {
@ -35,4 +38,9 @@ fn main() {
Foo::A4 => {},
_ => {},
}
match 3 {
Foo::A5..5 => {}
_ => {}
}
}

View file

@ -26,16 +26,16 @@ params: [
body:
Expr {
ty: bool
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
kind:
Scope {
region_scope: Node(26)
lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).26))
region_scope: Node(28)
lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).28))
value:
Expr {
ty: bool
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
kind:
Block {
@ -47,7 +47,7 @@ body:
expr:
Expr {
ty: bool
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
kind:
Scope {
@ -56,14 +56,14 @@ body:
value:
Expr {
ty: bool
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
kind:
Match {
scrutinee:
Expr {
ty: Foo
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
kind:
Scope {
@ -72,7 +72,7 @@ body:
value:
Expr {
ty: Foo
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
kind:
VarRef {
@ -123,16 +123,16 @@ body:
body:
Expr {
ty: bool
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(13)), backwards_incompatible: None }
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(14)), backwards_incompatible: None }
span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
kind:
Scope {
region_scope: Node(14)
lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).14))
region_scope: Node(15)
lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).15))
value:
Expr {
ty: bool
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(13)), backwards_incompatible: None }
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(14)), backwards_incompatible: None }
span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
kind:
Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false)
@ -140,8 +140,8 @@ body:
}
}
}
lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).13))
scope: Node(13)
lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).14))
scope: Node(14)
span: $DIR/thir-tree-match.rs:17:9: 17:40 (#0)
}
Arm {
@ -175,16 +175,16 @@ body:
body:
Expr {
ty: bool
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(19)), backwards_incompatible: None }
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(20)), backwards_incompatible: None }
span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
kind:
Scope {
region_scope: Node(20)
lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).20))
region_scope: Node(21)
lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).21))
value:
Expr {
ty: bool
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(19)), backwards_incompatible: None }
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(20)), backwards_incompatible: None }
span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
kind:
Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false)
@ -192,8 +192,8 @@ body:
}
}
}
lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).19))
scope: Node(19)
lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).20))
scope: Node(20)
span: $DIR/thir-tree-match.rs:18:9: 18:32 (#0)
}
Arm {
@ -219,16 +219,16 @@ body:
body:
Expr {
ty: bool
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
kind:
Scope {
region_scope: Node(25)
lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).25))
region_scope: Node(27)
lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).27))
value:
Expr {
ty: bool
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
kind:
Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false)
@ -236,8 +236,8 @@ body:
}
}
}
lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).24))
scope: Node(24)
lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).26))
scope: Node(26)
span: $DIR/thir-tree-match.rs:19:9: 19:28 (#0)
}
]