Implement &pin patterns and ref pin bindings
This commit is contained in:
parent
f5ccdae676
commit
276053175d
20 changed files with 44 additions and 39 deletions
|
|
@ -55,7 +55,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
|
|||
| PatKind::Err(_) => false,
|
||||
PatKind::Struct(_, a, etc) => etc.is_none() && 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::Ref(x, _, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x),
|
||||
PatKind::Expr(_) => true,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(
|
|||
let mut snippet = make_iterator_snippet(cx, arg, &mut applicability);
|
||||
// Checks if `pat` is a single reference to a binding (`&x`)
|
||||
let is_ref_to_binding =
|
||||
matches!(pat.kind, PatKind::Ref(inner, _) if matches!(inner.kind, PatKind::Binding(..)));
|
||||
matches!(pat.kind, PatKind::Ref(inner, _, _) if matches!(inner.kind, PatKind::Binding(..)));
|
||||
// If `pat` is not a binding or a reference to a binding (`x` or `&x`)
|
||||
// we need to map it to the binding returned by the function (i.e. `.map(|(x, _)| x)`)
|
||||
if !(matches!(pat.kind, PatKind::Binding(..)) || is_ref_to_binding) {
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ fn check_iter(
|
|||
),
|
||||
);
|
||||
},
|
||||
hir::PatKind::Ref(pat, _) => make_span_lint_and_sugg(
|
||||
hir::PatKind::Ref(pat, _, _) => make_span_lint_and_sugg(
|
||||
cx,
|
||||
parent_expr_span,
|
||||
format!(
|
||||
|
|
@ -196,7 +196,7 @@ fn check_to_owned(
|
|||
&& let filter_body = cx.tcx.hir_body(closure.body)
|
||||
&& let [filter_params] = filter_body.params
|
||||
&& msrv.meets(cx, msrvs::STRING_RETAIN)
|
||||
&& let hir::PatKind::Ref(pat, _) = filter_params.pat.kind
|
||||
&& let hir::PatKind::Ref(pat, _, _) = filter_params.pat.kind
|
||||
{
|
||||
make_span_lint_and_sugg(
|
||||
cx,
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ fn is_variant_or_wildcard(cx: &LateContext<'_>, pat: &Pat<'_>, can_be_wild: bool
|
|||
.is_lang_item(cx, ResultErr)
|
||||
== must_match_err
|
||||
},
|
||||
PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _) => {
|
||||
PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _, _) => {
|
||||
is_variant_or_wildcard(cx, pat, can_be_wild, must_match_err)
|
||||
},
|
||||
_ => false,
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ pub(super) fn try_parse_pattern<'tcx>(
|
|||
) -> Option<OptionPat<'tcx>> {
|
||||
match pat.kind {
|
||||
PatKind::Wild => Some(OptionPat::Wild),
|
||||
PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
|
||||
PatKind::Ref(pat, _, _) => f(cx, pat, ref_count + 1, ctxt),
|
||||
PatKind::Expr(PatExpr {
|
||||
kind: PatExprKind::Path(qpath),
|
||||
hir_id,
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ where
|
|||
}
|
||||
|
||||
let remaining_suggs = pats.filter_map(|pat| {
|
||||
if let PatKind::Ref(refp, _) = pat.kind {
|
||||
if let PatKind::Ref(refp, _, _) = pat.kind {
|
||||
Some((pat.span, snippet(cx, refp.span, "..").to_string()))
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ impl<'a> NormalizedPat<'a> {
|
|||
PatKind::Binding(.., Some(pat))
|
||||
| PatKind::Box(pat)
|
||||
| PatKind::Deref(pat)
|
||||
| PatKind::Ref(pat, _)
|
||||
| PatKind::Ref(pat, _, _)
|
||||
| PatKind::Guard(pat, _) => Self::from_pat(cx, arena, pat),
|
||||
PatKind::Never => Self::Never,
|
||||
PatKind::Struct(ref path, fields, _) => {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv:
|
|||
&& !pat_contains_disallowed_or(cx, arm.pat, msrv)
|
||||
{
|
||||
let pat_span = match (arm.pat.kind, binding.byref_ident) {
|
||||
(PatKind::Ref(pat, _), Some(_)) => pat.span,
|
||||
(PatKind::Ref(pat, _, _), Some(_)) => pat.span,
|
||||
(PatKind::Ref(..), None) | (_, Some(_)) => continue,
|
||||
_ => arm.pat.span,
|
||||
};
|
||||
|
|
@ -49,7 +49,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv:
|
|||
&& !pat_contains_disallowed_or(cx, let_expr.pat, msrv)
|
||||
{
|
||||
let pat_span = match (let_expr.pat.kind, binding.byref_ident) {
|
||||
(PatKind::Ref(pat, _), Some(_)) => pat.span,
|
||||
(PatKind::Ref(pat, _, _), Some(_)) => pat.span,
|
||||
(PatKind::Ref(..), None) | (_, Some(_)) => continue,
|
||||
_ => let_expr.pat.span,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ fn find_method_sugg_for_if_let<'tcx>(
|
|||
// also look inside refs
|
||||
// if we have &None for example, peel it so we can detect "if let None = x"
|
||||
let check_pat = match let_pat.kind {
|
||||
PatKind::Ref(inner, _mutability) => inner,
|
||||
PatKind::Ref(inner, _pinnedness, _mutability) => inner,
|
||||
_ => let_pat,
|
||||
};
|
||||
let op_ty = cx.typeck_results().expr_ty(let_expr);
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ impl<'a> PatState<'a> {
|
|||
},
|
||||
|
||||
// Patterns for things which can only contain a single sub-pattern.
|
||||
PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _) | PatKind::Box(pat) | PatKind::Deref(pat) => {
|
||||
PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _, _) | PatKind::Box(pat) | PatKind::Deref(pat) => {
|
||||
self.add_pat(cx, pat)
|
||||
},
|
||||
PatKind::Tuple([sub_pat], pos)
|
||||
|
|
|
|||
|
|
@ -404,7 +404,7 @@ fn is_find_or_filter<'a>(
|
|||
&& let filter_body = cx.tcx.hir_body(filter_body_id)
|
||||
&& let [filter_param] = filter_body.params
|
||||
// optional ref pattern: `filter(|&x| ..)`
|
||||
&& let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
|
||||
&& let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _, _) = filter_param.pat.kind {
|
||||
(ref_pat, true)
|
||||
} else {
|
||||
(filter_param.pat, false)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ fn is_method(
|
|||
fn pat_is_recv(ident: Ident, param: &hir::Pat<'_>) -> bool {
|
||||
match param.kind {
|
||||
hir::PatKind::Binding(_, _, other, _) => ident == other,
|
||||
hir::PatKind::Ref(pat, _) => pat_is_recv(ident, pat),
|
||||
hir::PatKind::Ref(pat, _, _) => pat_is_recv(ident, pat),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ pub(super) fn check<'tcx>(
|
|||
}
|
||||
|
||||
match it.kind {
|
||||
PatKind::Binding(BindingMode(_, Mutability::Mut), _, _, _) | PatKind::Ref(_, Mutability::Mut) => {
|
||||
PatKind::Binding(BindingMode(_, Mutability::Mut), _, _, _) | PatKind::Ref(_, _, Mutability::Mut) => {
|
||||
to_be_discarded = true;
|
||||
false
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, LangItem};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::mir::Mutability;
|
||||
use rustc_middle::mir::{Mutability, Pinnedness};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::adjustment::Adjust;
|
||||
use rustc_span::symbol::Ident;
|
||||
|
|
@ -50,7 +50,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_
|
|||
let closure_body = cx.tcx.hir_body(body);
|
||||
let closure_expr = peel_blocks(closure_body.value);
|
||||
match closure_body.params[0].pat.kind {
|
||||
hir::PatKind::Ref(inner, Mutability::Not) => {
|
||||
hir::PatKind::Ref(inner, Pinnedness::Not, Mutability::Not) => {
|
||||
if let hir::PatKind::Binding(hir::BindingMode::NONE, .., name, None) = inner.kind
|
||||
&& ident_eq(name, closure_expr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BindingMode, Mutability, Node, Pat, PatKind};
|
||||
use rustc_hir::{BindingMode, Mutability, Node, Pat, PatKind, Pinnedness};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ declare_lint_pass!(NeedlessBorrowedRef => [NEEDLESS_BORROWED_REFERENCE]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
|
||||
fn check_pat(&mut self, cx: &LateContext<'tcx>, ref_pat: &'tcx Pat<'_>) {
|
||||
if let PatKind::Ref(pat, Mutability::Not) = ref_pat.kind
|
||||
if let PatKind::Ref(pat, Pinnedness::Not, Mutability::Not) = ref_pat.kind
|
||||
&& !ref_pat.span.from_expansion()
|
||||
&& cx
|
||||
.tcx
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use clippy_utils::msrvs::{self, MsrvStack};
|
|||
use clippy_utils::over;
|
||||
use rustc_ast::PatKind::*;
|
||||
use rustc_ast::mut_visit::*;
|
||||
use rustc_ast::{self as ast, DUMMY_NODE_ID, Mutability, Pat, PatKind};
|
||||
use rustc_ast::{self as ast, DUMMY_NODE_ID, Mutability, Pat, PatKind, Pinnedness};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::thin_vec::{ThinVec, thin_vec};
|
||||
use rustc_errors::Applicability;
|
||||
|
|
@ -151,8 +151,8 @@ fn insert_necessary_parens(pat: &mut Box<Pat>) {
|
|||
walk_pat(self, pat);
|
||||
let target = match &mut pat.kind {
|
||||
// `i @ a | b`, `box a | b`, and `& mut? a | b`.
|
||||
Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p,
|
||||
Ref(p, Mutability::Not) if matches!(p.kind, Ident(BindingMode::MUT, ..)) => p, // `&(mut x)`
|
||||
Ident(.., Some(p)) | Box(p) | Ref(p, _, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p,
|
||||
Ref(p, Pinnedness::Not, Mutability::Not) if matches!(p.kind, Ident(BindingMode::MUT, ..)) => p, // `&(mut x)`
|
||||
_ => return,
|
||||
};
|
||||
target.kind = Paren(Box::new(take_pat(target)));
|
||||
|
|
@ -241,7 +241,8 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<Pat>, focus_idx: usize
|
|||
// Skip immutable refs, as grouping them saves few characters,
|
||||
// and almost always requires adding parens (increasing noisiness).
|
||||
// In the case of only two patterns, replacement adds net characters.
|
||||
| Ref(_, Mutability::Not)
|
||||
// FIXME(pin_ergonomics): handle pinned patterns
|
||||
| Ref(_, _, Mutability::Not)
|
||||
// Dealt with elsewhere.
|
||||
| Or(_) | Paren(_) | Deref(_) | Guard(..) => false,
|
||||
// Transform `box x | ... | box y` into `box (x | y)`.
|
||||
|
|
@ -254,10 +255,10 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<Pat>, focus_idx: usize
|
|||
|k| always_pat!(k, Box(p) => *p),
|
||||
),
|
||||
// Transform `&mut x | ... | &mut y` into `&mut (x | y)`.
|
||||
Ref(target, Mutability::Mut) => extend_with_matching(
|
||||
Ref(target, _, Mutability::Mut) => extend_with_matching(
|
||||
target, start, alternatives,
|
||||
|k| matches!(k, Ref(_, Mutability::Mut)),
|
||||
|k| always_pat!(k, Ref(p, _) => *p),
|
||||
|k| matches!(k, Ref(_, _, Mutability::Mut)),
|
||||
|k| always_pat!(k, Ref(p, _, _) => *p),
|
||||
),
|
||||
// Transform `b @ p0 | ... b @ p1` into `b @ (p0 | p1)`.
|
||||
Ident(b1, i1, Some(target)) => extend_with_matching(
|
||||
|
|
|
|||
|
|
@ -793,9 +793,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
kind!("Deref({pat})");
|
||||
self.pat(pat);
|
||||
},
|
||||
PatKind::Ref(pat, muta) => {
|
||||
PatKind::Ref(pat, pinn, muta) => {
|
||||
bind!(self, pat);
|
||||
kind!("Ref({pat}, Mutability::{muta:?})");
|
||||
kind!("Ref({pat}, Pinning::{pinn:?}, Mutability::{muta:?})");
|
||||
self.pat(pat);
|
||||
},
|
||||
PatKind::Guard(pat, cond) => {
|
||||
|
|
|
|||
|
|
@ -45,9 +45,8 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
|
|||
&& eq_expr_opt(lt.as_deref(), rt.as_deref())
|
||||
&& eq_range_end(&le.node, &re.node)
|
||||
},
|
||||
(Box(l), Box(r))
|
||||
| (Ref(l, Mutability::Not), Ref(r, Mutability::Not))
|
||||
| (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
|
||||
(Box(l), Box(r)) => eq_pat(l, r),
|
||||
(Ref(l, l_pin, l_mut), Ref(r, r_pin, r_mut)) => l_pin == r_pin && l_mut == r_mut && eq_pat(l, r),
|
||||
(Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, eq_pat),
|
||||
(Path(lq, lp), Path(rq, rp)) => both(lq.as_deref(), rq.as_deref(), eq_qself) && eq_path(lp, rp),
|
||||
(TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ use rustc_data_structures::fx::FxHasher;
|
|||
use rustc_hir::MatchSource::TryDesugar;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{
|
||||
AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField,
|
||||
ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeKind,
|
||||
Node, Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
|
||||
AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, ByRef, Closure, ConstArg, ConstArgKind, Expr,
|
||||
ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime,
|
||||
LifetimeKind, Node, Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
|
||||
StructTailExpr, TraitBoundModifiers, Ty, TyKind, TyPat, TyPatKind,
|
||||
};
|
||||
use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};
|
||||
|
|
@ -538,7 +538,7 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
&& both(le.as_ref(), re.as_ref(), |a, b| self.eq_pat_expr(a, b))
|
||||
&& (li == ri)
|
||||
},
|
||||
(PatKind::Ref(le, lm), PatKind::Ref(re, rm)) => lm == rm && self.eq_pat(le, re),
|
||||
(PatKind::Ref(le, lp, lm), PatKind::Ref(re, rp, rm)) => lp == rp && lm == rm && self.eq_pat(le, re),
|
||||
(PatKind::Slice(ls, li, le), PatKind::Slice(rs, ri, re)) => {
|
||||
over(ls, rs, |l, r| self.eq_pat(l, r))
|
||||
&& over(le, re, |l, r| self.eq_pat(l, r))
|
||||
|
|
@ -1131,6 +1131,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Binding(BindingMode(by_ref, mutability), _, _, pat) => {
|
||||
std::mem::discriminant(by_ref).hash(&mut self.s);
|
||||
if let ByRef::Yes(pi, mu) = by_ref {
|
||||
std::mem::discriminant(pi).hash(&mut self.s);
|
||||
std::mem::discriminant(mu).hash(&mut self.s);
|
||||
}
|
||||
std::mem::discriminant(mutability).hash(&mut self.s);
|
||||
if let Some(pat) = pat {
|
||||
self.hash_pat(pat);
|
||||
|
|
@ -1152,8 +1156,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
}
|
||||
std::mem::discriminant(i).hash(&mut self.s);
|
||||
},
|
||||
PatKind::Ref(pat, mu) => {
|
||||
PatKind::Ref(pat, pi, mu) => {
|
||||
self.hash_pat(pat);
|
||||
std::mem::discriminant(pi).hash(&mut self.s);
|
||||
std::mem::discriminant(mu).hash(&mut self.s);
|
||||
},
|
||||
PatKind::Guard(pat, guard) => {
|
||||
|
|
|
|||
|
|
@ -1462,7 +1462,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
|
|||
PatKind::Missing => unreachable!(),
|
||||
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::Box(pat) | PatKind::Ref(pat, _, _) => is_refutable(cx, pat),
|
||||
PatKind::Expr(PatExpr {
|
||||
kind: PatExprKind::Path(qpath),
|
||||
hir_id,
|
||||
|
|
@ -1612,7 +1612,7 @@ pub fn is_lint_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) ->
|
|||
}
|
||||
|
||||
pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> {
|
||||
while let PatKind::Ref(subpat, _) = pat.kind {
|
||||
while let PatKind::Ref(subpat, _, _) = pat.kind {
|
||||
pat = subpat;
|
||||
}
|
||||
pat
|
||||
|
|
@ -2157,7 +2157,7 @@ where
|
|||
/// references removed.
|
||||
pub fn peel_hir_pat_refs<'a>(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
|
||||
fn peel<'a>(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
|
||||
if let PatKind::Ref(pat, _) = pat.kind {
|
||||
if let PatKind::Ref(pat, _, _) = pat.kind {
|
||||
peel(pat, count + 1)
|
||||
} else {
|
||||
(pat, count)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue