Exhaustively handle expressions in patterns

This commit is contained in:
Oli Scherer 2024-12-11 16:50:45 +00:00
parent 5df69191cb
commit c9365dd09f
36 changed files with 447 additions and 197 deletions

View File

@ -102,17 +102,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let kind = match &e.kind { let kind = match &e.kind {
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
ExprKind::ConstBlock(c) => { ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)),
let c = self.with_new_scopes(c.value.span, |this| {
let def_id = this.local_def_id(c.id);
hir::ConstBlock {
def_id,
hir_id: this.lower_node_id(c.id),
body: this.lower_const_body(c.value.span, Some(&c.value)),
}
});
hir::ExprKind::ConstBlock(c)
}
ExprKind::Repeat(expr, count) => { ExprKind::Repeat(expr, count) => {
let expr = self.lower_expr(expr); let expr = self.lower_expr(expr);
let count = self.lower_array_length_to_const_arg(count); let count = self.lower_array_length_to_const_arg(count);
@ -153,18 +143,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let ohs = self.lower_expr(ohs); let ohs = self.lower_expr(ohs);
hir::ExprKind::Unary(op, ohs) hir::ExprKind::Unary(op, ohs)
} }
ExprKind::Lit(token_lit) => { ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)),
let lit_kind = match LitKind::from_token_lit(*token_lit) {
Ok(lit_kind) => lit_kind,
Err(err) => {
let guar =
report_lit_error(&self.tcx.sess.psess, err, *token_lit, e.span);
LitKind::Err(guar)
}
};
let lit = self.arena.alloc(respan(self.lower_span(e.span), lit_kind));
hir::ExprKind::Lit(lit)
}
ExprKind::IncludedBytes(bytes) => { ExprKind::IncludedBytes(bytes) => {
let lit = self.arena.alloc(respan( let lit = self.arena.alloc(respan(
self.lower_span(e.span), self.lower_span(e.span),
@ -403,6 +382,32 @@ impl<'hir> LoweringContext<'_, 'hir> {
}) })
} }
pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {
self.with_new_scopes(c.value.span, |this| {
let def_id = this.local_def_id(c.id);
hir::ConstBlock {
def_id,
hir_id: this.lower_node_id(c.id),
body: this.lower_const_body(c.value.span, Some(&c.value)),
}
})
}
pub(crate) fn lower_lit(
&mut self,
token_lit: &token::Lit,
span: Span,
) -> &'hir Spanned<LitKind> {
let lit_kind = match LitKind::from_token_lit(*token_lit) {
Ok(lit_kind) => lit_kind,
Err(err) => {
let guar = report_lit_error(&self.tcx.sess.psess, err, *token_lit, span);
LitKind::Err(guar)
}
};
self.arena.alloc(respan(self.lower_span(span), lit_kind))
}
fn lower_unop(&mut self, u: UnOp) -> hir::UnOp { fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
match u { match u {
UnOp::Deref => hir::UnOp::Deref, UnOp::Deref => hir::UnOp::Deref,

View File

@ -209,6 +209,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
}); });
} }
fn visit_pat_expr(&mut self, expr: &'hir PatExpr<'hir>) {
self.insert(expr.span, expr.hir_id, Node::PatExpr(expr));
self.with_parent(expr.hir_id, |this| {
intravisit::walk_pat_expr(this, expr);
});
}
fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) { fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) {
self.insert(field.span, field.hir_id, Node::PatField(field)); self.insert(field.span, field.hir_id, Node::PatField(field));
self.with_parent(field.hir_id, |this| { self.with_parent(field.hir_id, |this| {

View File

@ -35,6 +35,7 @@
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(assert_matches)] #![feature(assert_matches)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(if_let_guard)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(rustdoc_internals)] #![feature(rustdoc_internals)]
#![warn(unreachable_pub)] #![warn(unreachable_pub)]

View File

@ -1,9 +1,12 @@
use std::sync::Arc;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::*; use rustc_ast::*;
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_span::source_map::Spanned; use rustc_middle::span_bug;
use rustc_span::source_map::{Spanned, respan};
use rustc_span::{Ident, Span}; use rustc_span::{Ident, Span};
use super::errors::{ use super::errors::{
@ -367,24 +370,54 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// } // }
// m!(S); // m!(S);
// ``` // ```
fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> { fn lower_expr_within_pat(
match &expr.kind { &mut self,
ExprKind::Lit(..) expr: &Expr,
| ExprKind::ConstBlock(..) allow_paths: bool,
| ExprKind::IncludedBytes(..) ) -> &'hir hir::PatExpr<'hir> {
| ExprKind::Err(_) let err = |guar| hir::PatExprKind::Lit {
| ExprKind::Dummy => {} lit: self.arena.alloc(respan(self.lower_span(expr.span), LitKind::Err(guar))),
ExprKind::Path(..) if allow_paths => {} negated: false,
ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} };
let kind = match &expr.kind {
ExprKind::Lit(lit) => {
hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: false }
}
ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)),
ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit {
lit: self.arena.alloc(respan(
self.lower_span(expr.span),
LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked),
)),
negated: false,
},
ExprKind::Err(guar) => err(*guar),
ExprKind::Dummy => span_bug!(expr.span, "lowered ExprKind::Dummy"),
ExprKind::Path(qself, path) if allow_paths => hir::PatExprKind::Path(self.lower_qpath(
expr.id,
qself,
path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
)),
ExprKind::Unary(UnOp::Neg, inner) if let ExprKind::Lit(lit) = &inner.kind => {
hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: true }
}
_ => { _ => {
let pattern_from_macro = expr.is_approximately_pattern(); let pattern_from_macro = expr.is_approximately_pattern();
let guar = self.dcx().emit_err(ArbitraryExpressionInPattern { let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
span: expr.span, span: expr.span,
pattern_from_macro_note: pattern_from_macro, pattern_from_macro_note: pattern_from_macro,
}); });
return self.arena.alloc(self.expr_err(expr.span, guar)); err(guar)
} }
} };
self.lower_expr(expr) self.arena.alloc(hir::PatExpr {
hir_id: self.lower_node_id(expr.id),
span: expr.span,
kind,
})
} }
} }

View File

@ -1519,6 +1519,26 @@ impl fmt::Debug for DotDotPos {
} }
} }
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct PatExpr<'hir> {
pub hir_id: HirId,
pub span: Span,
pub kind: PatExprKind<'hir>,
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum PatExprKind<'hir> {
Lit {
lit: &'hir Lit,
// FIXME: move this into `Lit` and handle negated literal expressions
// once instead of matching on unop neg expressions everywhere.
negated: bool,
},
ConstBlock(ConstBlock),
/// A path pattern for a unit struct/variant or a (maybe-associated) constant.
Path(QPath<'hir>),
}
#[derive(Debug, Clone, Copy, HashStable_Generic)] #[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum PatKind<'hir> { pub enum PatKind<'hir> {
/// Represents a wildcard pattern (i.e., `_`). /// Represents a wildcard pattern (i.e., `_`).
@ -1564,13 +1584,13 @@ pub enum PatKind<'hir> {
Ref(&'hir Pat<'hir>, Mutability), Ref(&'hir Pat<'hir>, Mutability),
/// A literal. /// A literal.
Lit(&'hir Expr<'hir>), Lit(&'hir PatExpr<'hir>),
/// A guard pattern (e.g., `x if guard(x)`). /// A guard pattern (e.g., `x if guard(x)`).
Guard(&'hir Pat<'hir>, &'hir Expr<'hir>), Guard(&'hir Pat<'hir>, &'hir Expr<'hir>),
/// A range pattern (e.g., `1..=2` or `1..2`). /// A range pattern (e.g., `1..=2` or `1..2`).
Range(Option<&'hir Expr<'hir>>, Option<&'hir Expr<'hir>>, RangeEnd), Range(Option<&'hir PatExpr<'hir>>, Option<&'hir PatExpr<'hir>>, RangeEnd),
/// A slice pattern, `[before_0, ..., before_n, (slice, after_0, ..., after_n)?]`. /// A slice pattern, `[before_0, ..., before_n, (slice, after_0, ..., after_n)?]`.
/// ///
@ -4144,6 +4164,10 @@ pub enum Node<'hir> {
OpaqueTy(&'hir OpaqueTy<'hir>), OpaqueTy(&'hir OpaqueTy<'hir>),
Pat(&'hir Pat<'hir>), Pat(&'hir Pat<'hir>),
PatField(&'hir PatField<'hir>), PatField(&'hir PatField<'hir>),
/// Needed as its own node with its own HirId for tracking
/// the unadjusted type of literals within patterns
/// (e.g. byte str literals not being of slice type).
PatExpr(&'hir PatExpr<'hir>),
Arm(&'hir Arm<'hir>), Arm(&'hir Arm<'hir>),
Block(&'hir Block<'hir>), Block(&'hir Block<'hir>),
LetStmt(&'hir LetStmt<'hir>), LetStmt(&'hir LetStmt<'hir>),
@ -4200,6 +4224,7 @@ impl<'hir> Node<'hir> {
| Node::Block(..) | Node::Block(..)
| Node::Ctor(..) | Node::Ctor(..)
| Node::Pat(..) | Node::Pat(..)
| Node::PatExpr(..)
| Node::Arm(..) | Node::Arm(..)
| Node::LetStmt(..) | Node::LetStmt(..)
| Node::Crate(..) | Node::Crate(..)

View File

@ -342,6 +342,9 @@ pub trait Visitor<'v>: Sized {
fn visit_pat_field(&mut self, f: &'v PatField<'v>) -> Self::Result { fn visit_pat_field(&mut self, f: &'v PatField<'v>) -> Self::Result {
walk_pat_field(self, f) walk_pat_field(self, f)
} }
fn visit_pat_expr(&mut self, expr: &'v PatExpr<'v>) -> Self::Result {
walk_pat_expr(self, expr)
}
fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result { fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
walk_anon_const(self, c) walk_anon_const(self, c)
} }
@ -685,10 +688,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_ident(ident));
visit_opt!(visitor, visit_pat, optional_subpattern); visit_opt!(visitor, visit_pat, optional_subpattern);
} }
PatKind::Lit(ref expression) => try_visit!(visitor.visit_expr(expression)), PatKind::Lit(ref expression) => try_visit!(visitor.visit_pat_expr(expression)),
PatKind::Range(ref lower_bound, ref upper_bound, _) => { PatKind::Range(ref lower_bound, ref upper_bound, _) => {
visit_opt!(visitor, visit_expr, lower_bound); visit_opt!(visitor, visit_pat_expr, lower_bound);
visit_opt!(visitor, visit_expr, upper_bound); visit_opt!(visitor, visit_pat_expr, upper_bound);
} }
PatKind::Never | PatKind::Wild | PatKind::Err(_) => (), PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => { PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
@ -710,6 +713,15 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'
visitor.visit_pat(field.pat) visitor.visit_pat(field.pat)
} }
pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>) -> V::Result {
try_visit!(visitor.visit_id(expr.hir_id));
match &expr.kind {
PatExprKind::Lit { .. } => V::Result::output(),
PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c),
PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, expr.hir_id, expr.span),
}
}
pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) -> V::Result { pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) -> V::Result {
try_visit!(visitor.visit_id(constant.hir_id)); try_visit!(visitor.visit_id(constant.hir_id));
visitor.visit_nested_body(constant.body) visitor.visit_nested_body(constant.body)

View File

@ -2449,17 +2449,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
Ty::new_error(tcx, err) Ty::new_error(tcx, err)
} }
hir::PatKind::Range(start, end, include_end) => { hir::PatKind::Range(start, end, include_end) => {
let expr_to_const = |expr: &'tcx hir::Expr<'tcx>| -> ty::Const<'tcx> { let expr_to_const = |expr: &'tcx hir::PatExpr<'tcx>| -> ty::Const<'tcx> {
let (expr, neg) = match expr.kind { let (c, c_ty) = match expr.kind {
hir::ExprKind::Unary(hir::UnOp::Neg, negated) => { hir::PatExprKind::Lit { lit, negated } => {
(negated, Some((expr.hir_id, expr.span)))
}
_ => (expr, None),
};
let (c, c_ty) = match &expr.kind {
hir::ExprKind::Lit(lit) => {
let lit_input = let lit_input =
LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() }; LitToConstInput { lit: &lit.node, ty, neg: negated };
let ct = match tcx.lit_to_const(lit_input) { let ct = match tcx.lit_to_const(lit_input) {
Ok(c) => c, Ok(c) => c,
Err(LitToConstError::Reported(err)) => { Err(LitToConstError::Reported(err)) => {
@ -2470,23 +2464,30 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
(ct, ty) (ct, ty)
} }
hir::ExprKind::Path(hir::QPath::Resolved( hir::PatExprKind::Path(hir::QPath::Resolved(
_, _,
path @ &hir::Path { path @ &hir::Path {
res: Res::Def(DefKind::ConstParam, def_id), res: Res::Def(DefKind::ConstParam, def_id),
.. ..
}, },
)) => { )) => {
let _ = self.prohibit_generic_args( match self.prohibit_generic_args(
path.segments.iter(), path.segments.iter(),
GenericsArgsErrExtend::Param(def_id), GenericsArgsErrExtend::Param(def_id),
); ) {
let ty = tcx Ok(()) => {
.type_of(def_id) let ty = tcx
.no_bound_vars() .type_of(def_id)
.expect("const parameter types cannot be generic"); .no_bound_vars()
let ct = self.lower_const_param(def_id, expr.hir_id); .expect("const parameter types cannot be generic");
(ct, ty) let ct = self.lower_const_param(def_id, expr.hir_id);
(ct, ty)
}
Err(guar) => (
ty::Const::new_error(tcx, guar),
Ty::new_error(tcx, guar),
),
}
} }
_ => { _ => {
@ -2497,9 +2498,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} }
}; };
self.record_ty(expr.hir_id, c_ty, expr.span); self.record_ty(expr.hir_id, c_ty, expr.span);
if let Some((id, span)) = neg {
self.record_ty(id, c_ty, span);
}
c c
}; };

View File

@ -199,6 +199,7 @@ impl<'a> State<'a> {
Node::OpaqueTy(o) => self.print_opaque_ty(o), Node::OpaqueTy(o) => self.print_opaque_ty(o),
Node::Pat(a) => self.print_pat(a), Node::Pat(a) => self.print_pat(a),
Node::PatField(a) => self.print_patfield(a), Node::PatField(a) => self.print_patfield(a),
Node::PatExpr(a) => self.print_pat_expr(a),
Node::Arm(a) => self.print_arm(a), Node::Arm(a) => self.print_arm(a),
Node::Infer(_) => self.word("_"), Node::Infer(_) => self.word("_"),
Node::PreciseCapturingNonLifetimeArg(param) => self.print_ident(param.ident), Node::PreciseCapturingNonLifetimeArg(param) => self.print_ident(param.ident),
@ -1849,6 +1850,19 @@ impl<'a> State<'a> {
} }
} }
fn print_pat_expr(&mut self, expr: &hir::PatExpr<'_>) {
match &expr.kind {
hir::PatExprKind::Lit { lit, negated } => {
if *negated {
self.word("-");
}
self.print_literal(lit);
}
hir::PatExprKind::ConstBlock(c) => self.print_inline_const(c),
hir::PatExprKind::Path(qpath) => self.print_qpath(qpath, true),
}
}
fn print_pat(&mut self, pat: &hir::Pat<'_>) { fn print_pat(&mut self, pat: &hir::Pat<'_>) {
self.maybe_print_comment(pat.span.lo()); self.maybe_print_comment(pat.span.lo());
self.ann.pre(self, AnnNode::Pat(pat)); self.ann.pre(self, AnnNode::Pat(pat));
@ -1966,17 +1980,17 @@ impl<'a> State<'a> {
self.pclose(); self.pclose();
} }
} }
PatKind::Lit(e) => self.print_expr(e), PatKind::Lit(e) => self.print_pat_expr(e),
PatKind::Range(begin, end, end_kind) => { PatKind::Range(begin, end, end_kind) => {
if let Some(expr) = begin { if let Some(expr) = begin {
self.print_expr(expr); self.print_pat_expr(expr);
} }
match end_kind { match end_kind {
RangeEnd::Included => self.word("..."), RangeEnd::Included => self.word("..."),
RangeEnd::Excluded => self.word(".."), RangeEnd::Excluded => self.word(".."),
} }
if let Some(expr) = end { if let Some(expr) = end {
self.print_expr(expr); self.print_pat_expr(expr);
} }
} }
PatKind::Slice(before, slice, after) => { PatKind::Slice(before, slice, after) => {

View File

@ -430,6 +430,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| hir::Node::AssocItemConstraint(_) | hir::Node::AssocItemConstraint(_)
| hir::Node::TraitRef(_) | hir::Node::TraitRef(_)
| hir::Node::PatField(_) | hir::Node::PatField(_)
| hir::Node::PatExpr(_)
| hir::Node::LetStmt(_) | hir::Node::LetStmt(_)
| hir::Node::Synthetic | hir::Node::Synthetic
| hir::Node::Err(_) | hir::Node::Err(_)
@ -1796,7 +1797,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
fn check_expr_const_block( pub(super) fn check_expr_const_block(
&self, &self,
block: &'tcx hir::ConstBlock, block: &'tcx hir::ConstBlock,
expected: Expectation<'tcx>, expected: Expectation<'tcx>,

View File

@ -1039,6 +1039,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
def_id, def_id,
span, span,
), ),
Res::Err => {
return (
Ty::new_error(
tcx,
tcx.dcx().span_delayed_bug(span, "could not resolve path {:?}"),
),
res,
);
}
_ => bug!("instantiate_value_path on {:?}", res), _ => bug!("instantiate_value_path on {:?}", res),
}; };

View File

@ -170,6 +170,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span, span,
.. ..
}) })
| hir::Node::PatExpr(&hir::PatExpr {
kind: hir::PatExprKind::Path(QPath::TypeRelative(rcvr, segment)),
span,
..
})
| hir::Node::Pat(&hir::Pat { | hir::Node::Pat(&hir::Pat {
kind: kind:
hir::PatKind::Path(QPath::TypeRelative(rcvr, segment)) hir::PatKind::Path(QPath::TypeRelative(rcvr, segment))

View File

@ -30,6 +30,7 @@ use tracing::{debug, instrument, trace};
use ty::VariantDef; use ty::VariantDef;
use super::report_unexpected_variant_res; use super::report_unexpected_variant_res;
use crate::expectation::Expectation;
use crate::gather_locals::DeclOrigin; use crate::gather_locals::DeclOrigin;
use crate::{FnCtxt, LoweredTy, errors}; use crate::{FnCtxt, LoweredTy, errors};
@ -398,7 +399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`. // 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. // Call `resolve_vars_if_possible` here for inline const blocks.
PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() { PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
ty::Ref(..) => AdjustMode::Pass, ty::Ref(..) => AdjustMode::Pass,
_ => AdjustMode::Peel, _ => AdjustMode::Peel,
}, },
@ -493,10 +494,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(expected, def_br, max_ref_mutbl) (expected, def_br, max_ref_mutbl)
} }
fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
let ty = match &lt.kind {
rustc_hir::PatExprKind::Lit { lit, .. } => {
self.check_expr_lit(lit, Expectation::NoExpectation)
}
rustc_hir::PatExprKind::ConstBlock(c) => {
self.check_expr_const_block(c, Expectation::NoExpectation)
}
rustc_hir::PatExprKind::Path(qpath) => {
let (res, opt_ty, segments) =
self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span);
self.instantiate_value_path(segments, opt_ty, res, lt.span, lt.span, lt.hir_id).0
}
};
self.write_ty(lt.hir_id, ty);
ty
}
fn check_pat_lit( fn check_pat_lit(
&self, &self,
span: Span, span: Span,
lt: &hir::Expr<'tcx>, lt: &hir::PatExpr<'tcx>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
ti: &TopInfo<'tcx>, ti: &TopInfo<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
@ -507,7 +526,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Byte string patterns behave the same way as array patterns // Byte string patterns behave the same way as array patterns
// They can denote both statically and dynamically-sized byte arrays. // They can denote both statically and dynamically-sized byte arrays.
let mut pat_ty = ty; let mut pat_ty = ty;
if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(..), .. }) = lt.kind { if let hir::PatExprKind::Lit {
lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
} = lt.kind
{
let expected = self.structurally_resolve_type(span, expected); let expected = self.structurally_resolve_type(span, expected);
if let ty::Ref(_, inner_ty, _) = *expected.kind() if let ty::Ref(_, inner_ty, _) = *expected.kind()
&& self.try_structurally_resolve_type(span, inner_ty).is_slice() && self.try_structurally_resolve_type(span, inner_ty).is_slice()
@ -524,7 +546,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
if self.tcx.features().string_deref_patterns() if self.tcx.features().string_deref_patterns()
&& let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind && let hir::PatExprKind::Lit {
lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
} = lt.kind
{ {
let tcx = self.tcx; let tcx = self.tcx;
let expected = self.resolve_vars_if_possible(expected); let expected = self.resolve_vars_if_possible(expected);
@ -565,15 +589,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn check_pat_range( fn check_pat_range(
&self, &self,
span: Span, span: Span,
lhs: Option<&'tcx hir::Expr<'tcx>>, lhs: Option<&'tcx hir::PatExpr<'tcx>>,
rhs: Option<&'tcx hir::Expr<'tcx>>, rhs: Option<&'tcx hir::PatExpr<'tcx>>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
ti: &TopInfo<'tcx>, ti: &TopInfo<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr { let calc_side = |opt_expr: Option<&'tcx hir::PatExpr<'tcx>>| match opt_expr {
None => None, None => None,
Some(expr) => { Some(expr) => {
let ty = self.check_expr(expr); let ty = self.check_pat_expr_unadjusted(expr);
// Check that the end-point is possibly of numeric or char type. // Check that the end-point is possibly of numeric or char type.
// The early check here is not for correctness, but rather better // The early check here is not for correctness, but rather better
// diagnostics (e.g. when `&str` is being matched, `expected` will // diagnostics (e.g. when `&str` is being matched, `expected` will
@ -1813,9 +1837,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} else if inexistent_fields.len() == 1 { } else if inexistent_fields.len() == 1 {
match pat_field.pat.kind { match pat_field.pat.kind {
PatKind::Lit(expr) PatKind::Lit(_)
if !self.may_coerce( if !self.may_coerce(
self.typeck_results.borrow().expr_ty(expr), self.typeck_results.borrow().node_type(pat_field.pat.hir_id),
self.field_ty(field.span, field_def, args), self.field_ty(field.span, field_def, args),
) => {} ) => {}
_ => { _ => {

View File

@ -147,15 +147,16 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
self.visit_body(body); self.visit_body(body);
self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause); self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause);
} }
hir::ExprKind::ConstBlock(anon_const) => {
let body = self.fcx.tcx.hir().body(anon_const.body);
self.visit_body(body);
}
_ => {} _ => {}
} }
intravisit::walk_expr(self, expr); intravisit::walk_expr(self, expr);
} }
fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
let body = self.fcx.tcx.hir().body(c.body);
self.visit_body(body);
}
} }
impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

View File

@ -246,6 +246,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
} }
} }
} }
fn visit_const_block(&mut self, span: Span, anon_const: &hir::ConstBlock) {
self.visit_node_id(span, anon_const.hir_id);
let body = self.tcx().hir().body(anon_const.body);
self.visit_body(body);
}
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -275,11 +282,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => { hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => {
self.visit_field_id(e.hir_id); self.visit_field_id(e.hir_id);
} }
hir::ExprKind::ConstBlock(anon_const) => { hir::ExprKind::ConstBlock(ref anon_const) => {
self.visit_node_id(e.span, anon_const.hir_id); self.visit_const_block(e.span, anon_const);
let body = self.tcx().hir().body(anon_const.body);
self.visit_body(body);
} }
_ => {} _ => {}
} }
@ -335,6 +339,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
intravisit::walk_pat(self, p); intravisit::walk_pat(self, p);
} }
fn visit_pat_expr(&mut self, expr: &'tcx hir::PatExpr<'tcx>) {
self.visit_node_id(expr.span, expr.hir_id);
if let hir::PatExprKind::ConstBlock(c) = &expr.kind {
self.visit_const_block(expr.span, c);
}
intravisit::walk_pat_expr(self, expr);
}
fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) { fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
intravisit::walk_local(self, l); intravisit::walk_local(self, l);
let var_ty = self.fcx.local_ty(l.span, l.hir_id); let var_ty = self.fcx.local_ty(l.span, l.hir_id);

View File

@ -938,6 +938,7 @@ impl<'hir> Map<'hir> {
Node::OpaqueTy(op) => op.span, Node::OpaqueTy(op) => op.span,
Node::Pat(pat) => pat.span, Node::Pat(pat) => pat.span,
Node::PatField(field) => field.span, Node::PatField(field) => field.span,
Node::PatExpr(lit) => lit.span,
Node::Arm(arm) => arm.span, Node::Arm(arm) => arm.span,
Node::Block(block) => block.span, Node::Block(block) => block.span,
Node::Ctor(..) => self.span_with_body(self.tcx.parent_hir_id(hir_id)), Node::Ctor(..) => self.span_with_body(self.tcx.parent_hir_id(hir_id)),
@ -1209,6 +1210,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
Node::OpaqueTy(_) => node_str("opaque type"), Node::OpaqueTy(_) => node_str("opaque type"),
Node::Pat(_) => node_str("pat"), Node::Pat(_) => node_str("pat"),
Node::PatField(_) => node_str("pattern field"), Node::PatField(_) => node_str("pattern field"),
Node::PatExpr(_) => node_str("pattern literal"),
Node::Param(_) => node_str("param"), Node::Param(_) => node_str("param"),
Node::Arm(_) => node_str("arm"), Node::Arm(_) => node_str("arm"),
Node::Block(_) => node_str("block"), Node::Block(_) => node_str("block"),

View File

@ -154,7 +154,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
fn lower_pattern_range_endpoint( fn lower_pattern_range_endpoint(
&mut self, &mut self,
expr: Option<&'tcx hir::Expr<'tcx>>, expr: Option<&'tcx hir::PatExpr<'tcx>>,
) -> Result< ) -> Result<
(Option<PatRangeBoundary<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>), (Option<PatRangeBoundary<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>),
ErrorGuaranteed, ErrorGuaranteed,
@ -200,13 +200,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// This is only called when the range is already known to be malformed. /// This is only called when the range is already known to be malformed.
fn error_on_literal_overflow( fn error_on_literal_overflow(
&self, &self,
expr: Option<&'tcx hir::Expr<'tcx>>, expr: Option<&'tcx hir::PatExpr<'tcx>>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
use hir::{ExprKind, UnOp};
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
let Some(mut expr) = expr else { let Some(expr) = expr else {
return Ok(()); return Ok(());
}; };
let span = expr.span; let span = expr.span;
@ -214,12 +213,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// We need to inspect the original expression, because if we only inspect the output of // We need to inspect the original expression, because if we only inspect the output of
// `eval_bits`, an overflowed value has already been wrapped around. // `eval_bits`, an overflowed value has already been wrapped around.
// We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint. // We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint.
let mut negated = false; let hir::PatExprKind::Lit { lit, negated } = expr.kind else {
if let ExprKind::Unary(UnOp::Neg, sub_expr) = expr.kind {
negated = true;
expr = sub_expr;
}
let ExprKind::Lit(lit) = expr.kind else {
return Ok(()); return Ok(());
}; };
let LitKind::Int(lit_val, _) = lit.node else { let LitKind::Int(lit_val, _) = lit.node else {
@ -248,8 +242,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
fn lower_pattern_range( fn lower_pattern_range(
&mut self, &mut self,
lo_expr: Option<&'tcx hir::Expr<'tcx>>, lo_expr: Option<&'tcx hir::PatExpr<'tcx>>,
hi_expr: Option<&'tcx hir::Expr<'tcx>>, hi_expr: Option<&'tcx hir::PatExpr<'tcx>>,
end: RangeEnd, end: RangeEnd,
ty: Ty<'tcx>, ty: Ty<'tcx>,
span: Span, span: Span,
@ -662,25 +656,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// The special case for negation exists to allow things like `-128_i8` /// The special case for negation exists to allow things like `-128_i8`
/// which would overflow if we tried to evaluate `128_i8` and then negate /// which would overflow if we tried to evaluate `128_i8` and then negate
/// afterwards. /// afterwards.
fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> { fn lower_lit(&mut self, expr: &'tcx hir::PatExpr<'tcx>) -> PatKind<'tcx> {
let (lit, neg) = match expr.kind { let (lit, neg) = match &expr.kind {
hir::ExprKind::Path(ref qpath) => { hir::PatExprKind::Path(qpath) => {
return self.lower_path(qpath, expr.hir_id, expr.span).kind; return self.lower_path(qpath, expr.hir_id, expr.span).kind;
} }
hir::ExprKind::ConstBlock(ref anon_const) => { hir::PatExprKind::ConstBlock(anon_const) => {
return self.lower_inline_const(anon_const, expr.hir_id, expr.span); return self.lower_inline_const(anon_const, expr.hir_id, expr.span);
} }
hir::ExprKind::Lit(ref lit) => (lit, false), hir::PatExprKind::Lit { lit, negated } => (lit, *negated),
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => {
let hir::ExprKind::Lit(ref lit) = expr.kind else {
span_bug!(expr.span, "not a literal: {:?}", expr);
};
(lit, true)
}
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
}; };
let ct_ty = self.typeck_results.expr_ty(expr); let ct_ty = self.typeck_results.node_type(expr.hir_id);
let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg }; let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
match self.tcx.at(expr.span).lit_to_const(lit_input) { match self.tcx.at(expr.span).lit_to_const(lit_input) {
Ok(constant) => self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind, Ok(constant) => self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind,

View File

@ -3,8 +3,11 @@ use clippy_utils::numeric_literal;
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::intravisit::{Visitor, walk_expr, walk_stmt}; use rustc_hir::intravisit::{Visitor, walk_expr, walk_pat, walk_stmt};
use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind, StructTailExpr}; use rustc_hir::{
Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Pat, PatExpr, PatExprKind, PatKind, Stmt, StmtKind,
StructTailExpr,
};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty}; use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty};
@ -219,6 +222,22 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> {
walk_expr(self, expr); walk_expr(self, expr);
} }
fn visit_pat(&mut self, pat: &'tcx Pat<'_>) {
match pat.kind {
PatKind::Lit(&PatExpr {
hir_id,
kind: PatExprKind::Lit { lit, .. },
..
}) => {
let ty = self.cx.typeck_results().node_type(hir_id);
self.check_lit(lit, ty, hir_id);
return;
},
_ => {},
}
walk_pat(self, pat)
}
fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
match stmt.kind { match stmt.kind {
// we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric` // we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric`

View File

@ -8,8 +8,8 @@ use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::{ use rustc_hir::{
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatKind, PathSegment, PrimTy, QPath, ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy,
TraitItemRef, TyKind, QPath, TraitItemRef, TyKind,
}; };
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
@ -163,7 +163,13 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
if let ExprKind::Let(lt) = expr.kind if let ExprKind::Let(lt) = expr.kind
&& match lt.pat.kind { && match lt.pat.kind {
PatKind::Slice([], None, []) => true, PatKind::Slice([], None, []) => true,
PatKind::Lit(lit) if is_empty_string(lit) => true, PatKind::Lit(lit) => match lit.kind {
PatExprKind::Lit { lit, .. } => match lit.node {
LitKind::Str(lit, _) => lit.as_str().is_empty(),
_ => false,
},
_ => false,
},
_ => false, _ => false,
} }
&& !expr.span.from_expansion() && !expr.span.from_expansion()

View File

@ -7,7 +7,7 @@ use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operator
use rustc_ast::LitKind::{Byte, Char}; use rustc_ast::LitKind::{Byte, Char};
use rustc_ast::ast::RangeLimits; use rustc_ast::ast::RangeLimits;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd}; use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd, PatExpr, PatExprKind, Lit};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
{ {
let arg = peel_ref_operators(cx, arg); let arg = peel_ref_operators(cx, arg);
let ty_sugg = get_ty_sugg(cx, arg, start); let ty_sugg = get_ty_sugg(cx, arg, start);
let range = check_range(start, end); let range = check_expr_range(start, end);
check_is_ascii(cx, expr.span, arg, &range, ty_sugg); check_is_ascii(cx, expr.span, arg, &range, ty_sugg);
} }
} }
@ -196,19 +196,34 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
} }
} }
fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange { fn check_expr_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
if let ExprKind::Lit(start_lit) = &start.kind if let ExprKind::Lit(start_lit) = &start.kind
&& let ExprKind::Lit(end_lit) = &end.kind && let ExprKind::Lit(end_lit) = &end.kind
{ {
match (&start_lit.node, &end_lit.node) { check_lit_range(start_lit, end_lit)
(Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
(Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
(Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter,
(Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter,
(Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
_ => CharRange::Otherwise,
}
} else { } else {
CharRange::Otherwise CharRange::Otherwise
} }
} }
fn check_range(start: &PatExpr<'_>, end: &PatExpr<'_>) -> CharRange {
if let PatExprKind::Lit{ lit: start_lit, negated: false } = &start.kind
&& let PatExprKind::Lit{ lit: end_lit, negated: false } = &end.kind
{
check_lit_range(start_lit, end_lit)
} else {
CharRange::Otherwise
}
}
fn check_lit_range(start_lit: &Lit, end_lit: &Lit) -> CharRange {
match (&start_lit.node, &end_lit.node) {
(Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
(Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
(Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter,
(Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter,
(Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
_ => CharRange::Otherwise,
}
}

View File

@ -3,7 +3,7 @@ use clippy_utils::source::SpanRangeExt;
use rustc_ast::LitKind; use rustc_ast::LitKind;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp}; use rustc_hir::{PatExpr, PatExprKind, PatKind, RangeEnd};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
@ -38,14 +38,13 @@ declare_clippy_lint! {
} }
declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]); declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]);
fn expr_as_i128(expr: &Expr<'_>) -> Option<i128> { fn expr_as_i128(expr: &PatExpr<'_>) -> Option<i128> {
if let ExprKind::Unary(UnOp::Neg, expr) = expr.kind { if let PatExprKind::Lit { lit, negated } = expr.kind
expr_as_i128(expr).map(|num| -num)
} else if let ExprKind::Lit(lit) = expr.kind
&& let LitKind::Int(num, _) = lit.node && let LitKind::Int(num, _) = lit.node
{ {
// Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now. // Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now.
num.get().try_into().ok() let n = i128::try_from(num.get()).ok()?;
Some(if negated { -n } else { n })
} else { } else {
None None
} }
@ -58,7 +57,7 @@ struct Num {
} }
impl Num { impl Num {
fn new(expr: &Expr<'_>) -> Option<Self> { fn new(expr: &PatExpr<'_>) -> Option<Self> {
Some(Self { Some(Self {
val: expr_as_i128(expr)?, val: expr_as_i128(expr)?,
span: expr.span, span: expr.span,

View File

@ -4,7 +4,7 @@ use clippy_utils::source::{expr_block, snippet};
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use rustc_ast::LitKind; use rustc_ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Arm, Expr, ExprKind, PatKind}; use rustc_hir::{Arm, Expr, PatExprKind, PatKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
@ -22,7 +22,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
if arms.len() == 2 { if arms.len() == 2 {
// no guards // no guards
let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind { let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
if let ExprKind::Lit(lit) = arm_bool.kind { if let PatExprKind::Lit { lit, .. } = arm_bool.kind {
match lit.node { match lit.node {
LitKind::Bool(true) => Some((arms[0].body, arms[1].body)), LitKind::Bool(true) => Some((arms[0].body, arms[1].body)),
LitKind::Bool(false) => Some((arms[1].body, arms[0].body)), LitKind::Bool(false) => Some((arms[1].body, arms[0].body)),

View File

@ -7,7 +7,7 @@ use rustc_arena::DroplessArena;
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd}; use rustc_hir::{Arm, Expr, PatExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd};
use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
use rustc_lint::{LateContext, LintContext}; use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty; use rustc_middle::ty;
@ -313,7 +313,7 @@ impl<'a> NormalizedPat<'a> {
}, },
PatKind::Lit(e) => match &e.kind { PatKind::Lit(e) => match &e.kind {
// TODO: Handle negative integers. They're currently treated as a wild match. // TODO: Handle negative integers. They're currently treated as a wild match.
ExprKind::Lit(lit) => match lit.node { PatExprKind::Lit{ lit, negated: false } => match lit.node {
LitKind::Str(sym, _) => Self::LitStr(sym), LitKind::Str(sym, _) => Self::LitStr(sym),
LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes), LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes),
LitKind::Byte(val) => Self::LitInt(val.into()), LitKind::Byte(val) => Self::LitInt(val.into()),
@ -330,7 +330,7 @@ impl<'a> NormalizedPat<'a> {
let start = match start { let start = match start {
None => 0, None => 0,
Some(e) => match &e.kind { Some(e) => match &e.kind {
ExprKind::Lit(lit) => match lit.node { PatExprKind::Lit { lit, negated: false } => match lit.node {
LitKind::Int(val, _) => val.get(), LitKind::Int(val, _) => val.get(),
LitKind::Char(val) => val.into(), LitKind::Char(val) => val.into(),
LitKind::Byte(val) => val.into(), LitKind::Byte(val) => val.into(),
@ -342,7 +342,7 @@ impl<'a> NormalizedPat<'a> {
let (end, bounds) = match end { let (end, bounds) = match end {
None => (u128::MAX, RangeEnd::Included), None => (u128::MAX, RangeEnd::Included),
Some(e) => match &e.kind { Some(e) => match &e.kind {
ExprKind::Lit(lit) => match lit.node { PatExprKind::Lit { lit, negated: false } => match lit.node {
LitKind::Int(val, _) => (val.get(), bounds), LitKind::Int(val, _) => (val.get(), bounds),
LitKind::Char(val) => (val.into(), bounds), LitKind::Char(val) => (val.into(), bounds),
LitKind::Byte(val) => (val.into(), bounds), LitKind::Byte(val) => (val.into(), bounds),

View File

@ -5,7 +5,7 @@ use clippy_utils::ty::is_type_lang_item;
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::intravisit::{Visitor, walk_expr};
use rustc_hir::{Arm, Expr, ExprKind, LangItem, PatKind}; use rustc_hir::{Arm, Expr, ExprKind, PatExpr, PatExprKind, LangItem, PatKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::Span; use rustc_span::Span;
@ -85,8 +85,8 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(
}; };
for arm in arms { for arm in arms {
if let PatKind::Lit(Expr { if let PatKind::Lit(PatExpr {
kind: ExprKind::Lit(lit), kind: PatExprKind::Lit { lit, negated: false },
.. ..
}) = arm.pat.kind }) = arm.pat.kind
&& let LitKind::Str(symbol, _) = lit.node && let LitKind::Str(symbol, _) = lit.node

View File

@ -8,7 +8,7 @@ use clippy_utils::{
}; };
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone; use rustc_hir::LangItem::OptionNone;
use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatKind, Path, QPath}; use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatExprKind, PatKind, Path, QPath};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::sym; use rustc_span::sym;
@ -133,7 +133,7 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>
}, },
// compare match_expr ty with RetTy in `fn foo() -> RetTy` // compare match_expr ty with RetTy in `fn foo() -> RetTy`
Node::Item(item) => { Node::Item(item) => {
if let ItemKind::Fn{ .. } = item.kind { if let ItemKind::Fn { .. } = item.kind {
let output = cx let output = cx
.tcx .tcx
.fn_sig(item.owner_id) .fn_sig(item.owner_id)
@ -189,8 +189,12 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
}); });
}, },
// Example: `5 => 5` // Example: `5 => 5`
(PatKind::Lit(pat_lit_expr), ExprKind::Lit(expr_spanned)) => { (PatKind::Lit(pat_expr_expr), ExprKind::Lit(expr_spanned)) => {
if let ExprKind::Lit(pat_spanned) = &pat_lit_expr.kind { if let PatExprKind::Lit {
lit: pat_spanned,
negated: false,
} = &pat_expr_expr.kind
{
return pat_spanned.node == expr_spanned.node; return pat_spanned.node == expr_spanned.node;
} }
}, },

View File

@ -34,13 +34,13 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
if let Arm { pat, guard: None, .. } = *arm { if let Arm { pat, guard: None, .. } = *arm {
if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind { if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
let lhs_const = if let Some(lhs) = lhs { let lhs_const = if let Some(lhs) = lhs {
ConstEvalCtxt::new(cx).eval(lhs)? ConstEvalCtxt::new(cx).eval_pat_expr(lhs)?
} else { } else {
let min_val_const = ty.numeric_min_val(cx.tcx)?; let min_val_const = ty.numeric_min_val(cx.tcx)?;
mir_to_const(cx.tcx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))? mir_to_const(cx.tcx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))?
}; };
let rhs_const = if let Some(rhs) = rhs { let rhs_const = if let Some(rhs) = rhs {
ConstEvalCtxt::new(cx).eval(rhs)? ConstEvalCtxt::new(cx).eval_pat_expr(rhs)?
} else { } else {
let max_val_const = ty.numeric_max_val(cx.tcx)?; let max_val_const = ty.numeric_max_val(cx.tcx)?;
mir_to_const(cx.tcx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))? mir_to_const(cx.tcx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))?
@ -58,7 +58,9 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
} }
if let PatKind::Lit(value) = pat.kind { if let PatKind::Lit(value) = pat.kind {
let value = ConstEvalCtxt::new(cx).eval_full_int(value)?; let value = ConstEvalCtxt::new(cx)
.eval_pat_expr(value)?
.int_value(cx.tcx, cx.typeck_results().node_type(pat.hir_id))?;
return Some(SpannedRange { return Some(SpannedRange {
span: pat.span, span: pat.span,
node: (value, EndBound::Included(value)), node: (value, EndBound::Included(value)),

View File

@ -9,7 +9,7 @@ use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp}; use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp, PatExprKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_middle::ty::{self, GenericArgKind, Ty};
use rustc_span::{Span, Symbol, sym}; use rustc_span::{Span, Symbol, sym};
@ -75,7 +75,7 @@ fn find_match_true<'tcx>(
message: &'static str, message: &'static str,
) { ) {
if let PatKind::Lit(lit) = pat.kind if let PatKind::Lit(lit) = pat.kind
&& let ExprKind::Lit(lit) = lit.kind && let PatExprKind::Lit{ lit, negated: false } = lit.kind
&& let LitKind::Bool(pat_is_true) = lit.node && let LitKind::Bool(pat_is_true) = lit.node
{ {
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;

View File

@ -9,7 +9,7 @@ use rustc_arena::DroplessArena;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{Visitor, walk_pat}; use rustc_hir::intravisit::{Visitor, walk_pat};
use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind}; use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind, PatExpr, PatExprKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{self, AdtDef, TyCtxt, TypeckResults, VariantDef}; use rustc_middle::ty::{self, AdtDef, TyCtxt, TypeckResults, VariantDef};
use rustc_span::{Span, sym}; use rustc_span::{Span, sym};
@ -126,8 +126,8 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
// scrutinee derives PartialEq and the pattern is a constant. // scrutinee derives PartialEq and the pattern is a constant.
let pat_ref_count = match pat.kind { let pat_ref_count = match pat.kind {
// string literals are already a reference. // string literals are already a reference.
PatKind::Lit(Expr { PatKind::Lit(PatExpr {
kind: ExprKind::Lit(lit), kind: PatExprKind::Lit { lit, negated: false },
.. ..
}) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1, }) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1,
_ => pat_ref_count, _ => pat_ref_count,

View File

@ -11,7 +11,7 @@ use clippy_utils::visitors::{Descend, for_each_expr};
use itertools::Itertools; use itertools::Itertools;
use rustc_ast::{BinOpKind, LitKind}; use rustc_ast::{BinOpKind, LitKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, PatKind}; use rustc_hir::{Expr, ExprKind, PatExprKind, PatKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
@ -171,7 +171,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<
return ControlFlow::Break(()); return ControlFlow::Break(());
} }
if arm.pat.walk_short(|pat| match pat.kind { if arm.pat.walk_short(|pat| match pat.kind {
PatKind::Lit(expr) if let ExprKind::Lit(lit) = expr.kind => { PatKind::Lit(expr) if let PatExprKind::Lit { lit, negated: false } = expr.kind => {
if let LitKind::Char(_) = lit.node { if let LitKind::Char(_) = lit.node {
set_char_spans.push(lit.span); set_char_spans.push(lit.span);
} }

View File

@ -4,7 +4,7 @@ use rustc_ast::ast::{LitFloatType, LitKind};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{ use rustc_hir::{
self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind, self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind,
FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, StructTailExpr, TyKind, FnRetTy, HirId, Lit, PatExprKind, PatKind, QPath, StmtKind, StructTailExpr, TyKind,
}; };
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
@ -643,6 +643,27 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
self.expr(expr); self.expr(expr);
} }
fn pat_expr(&self, lit: &Binding<&hir::PatExpr<'_>>) {
let kind = |kind| chain!(self, "let PatExprKind::{kind} = {lit}.kind");
macro_rules! kind {
($($t:tt)*) => (kind(format_args!($($t)*)));
}
match lit.value.kind {
PatExprKind::Lit { lit, negated } => {
bind!(self, lit);
bind!(self, negated);
kind!("Lit{{ref {lit}, {negated} }}");
self.lit(lit);
},
PatExprKind::ConstBlock(_) => kind!("ConstBlock(_)"),
PatExprKind::Path(ref qpath) => {
bind!(self, qpath);
kind!("Path(ref {qpath})");
self.qpath(qpath);
},
}
}
fn pat(&self, pat: &Binding<&hir::Pat<'_>>) { fn pat(&self, pat: &Binding<&hir::Pat<'_>>) {
let kind = |kind| chain!(self, "let PatKind::{kind} = {pat}.kind"); let kind = |kind| chain!(self, "let PatKind::{kind} = {pat}.kind");
macro_rules! kind { macro_rules! kind {
@ -721,13 +742,13 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
PatKind::Lit(lit_expr) => { PatKind::Lit(lit_expr) => {
bind!(self, lit_expr); bind!(self, lit_expr);
kind!("Lit({lit_expr})"); kind!("Lit({lit_expr})");
self.expr(lit_expr); self.pat_expr(lit_expr);
}, },
PatKind::Range(start, end, end_kind) => { PatKind::Range(start, end, end_kind) => {
opt_bind!(self, start, end); opt_bind!(self, start, end);
kind!("Range({start}, {end}, RangeEnd::{end_kind:?})"); kind!("Range({start}, {end}, RangeEnd::{end_kind:?})");
start.if_some(|e| self.expr(e)); start.if_some(|e| self.pat_expr(e));
end.if_some(|e| self.expr(e)); end.if_some(|e| self.pat_expr(e));
}, },
PatKind::Slice(start, middle, end) => { PatKind::Slice(start, middle, end) => {
bind!(self, start, end); bind!(self, start, end);

View File

@ -4,7 +4,6 @@
//! executable MIR bodies, so we have to do this instead. //! executable MIR bodies, so we have to do this instead.
#![allow(clippy::float_cmp)] #![allow(clippy::float_cmp)]
use crate::macros::HirNode;
use crate::source::{SpanRangeExt, walk_span_to_context}; use crate::source::{SpanRangeExt, walk_span_to_context};
use crate::{clip, is_direct_expn_of, sext, unsext}; use crate::{clip, is_direct_expn_of, sext, unsext};
@ -13,7 +12,7 @@ use rustc_apfloat::ieee::{Half, Quad};
use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_ast::ast::{self, LitFloatType, LitKind};
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp, PatExpr, PatExprKind};
use rustc_lexer::tokenize; use rustc_lexer::tokenize;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::mir::ConstValue; use rustc_middle::mir::ConstValue;
@ -442,30 +441,48 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
} }
} }
pub fn eval_pat_expr(&self, pat_expr: &PatExpr<'_>) -> Option<Constant<'tcx>> {
match &pat_expr.kind {
PatExprKind::Lit { lit, negated } => {
let ty = self.typeck.node_type_opt(pat_expr.hir_id);
let val = lit_to_mir_constant(&lit.node, ty);
if *negated {
self.constant_negate(&val, ty?)
} else {
Some(val)
}
}
PatExprKind::ConstBlock(ConstBlock { body, ..}) => self.expr(self.tcx.hir().body(*body).value),
PatExprKind::Path(qpath) => self.qpath(qpath, pat_expr.hir_id),
}
}
fn qpath(&self, qpath: &QPath<'_>, hir_id: HirId) -> Option<Constant<'tcx>> {
let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, hir_id).opt_def_id() {
self.tcx.crate_name(def_id.krate) == sym::core
} else {
false
};
self.fetch_path_and_apply(qpath, hir_id, self.typeck.node_type(hir_id), |self_, result| {
let result = mir_to_const(self_.tcx, result)?;
// If source is already Constant we wouldn't want to override it with CoreConstant
self_.source.set(
if is_core_crate && !matches!(self_.source.get(), ConstantSource::Constant) {
ConstantSource::CoreConstant
} else {
ConstantSource::Constant
},
);
Some(result)
})
}
/// Simple constant folding: Insert an expression, get a constant or none. /// Simple constant folding: Insert an expression, get a constant or none.
fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> { fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
match e.kind { match e.kind {
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value), ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value),
ExprKind::DropTemps(e) => self.expr(e), ExprKind::DropTemps(e) => self.expr(e),
ExprKind::Path(ref qpath) => { ExprKind::Path(ref qpath) => self.qpath(qpath, e.hir_id),
let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, e.hir_id()).opt_def_id() {
self.tcx.crate_name(def_id.krate) == sym::core
} else {
false
};
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck.expr_ty(e), |self_, result| {
let result = mir_to_const(self_.tcx, result)?;
// If source is already Constant we wouldn't want to override it with CoreConstant
self_.source.set(
if is_core_crate && !matches!(self_.source.get(), ConstantSource::Constant) {
ConstantSource::CoreConstant
} else {
ConstantSource::Constant
},
);
Some(result)
})
},
ExprKind::Block(block, _) => self.block(block), ExprKind::Block(block, _) => self.block(block),
ExprKind::Lit(lit) => { ExprKind::Lit(lit) => {
if is_direct_expn_of(e.span, "cfg").is_some() { if is_direct_expn_of(e.span, "cfg").is_some() {

View File

@ -9,8 +9,8 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::{ use rustc_hir::{
AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField,
ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName,
Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty, Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr,
TyKind, TraitBoundModifiers, Ty, TyKind,
}; };
use rustc_lexer::{TokenKind, tokenize}; use rustc_lexer::{TokenKind, tokenize};
use rustc_lint::LateContext; use rustc_lint::LateContext;
@ -489,6 +489,24 @@ impl HirEqInterExpr<'_, '_, '_> {
li.name == ri.name && self.eq_pat(lp, rp) li.name == ri.name && self.eq_pat(lp, rp)
} }
fn eq_pat_expr(&mut self, left: &PatExpr<'_>, right: &PatExpr<'_>) -> bool {
match (&left.kind, &right.kind) {
(
&PatExprKind::Lit {
lit: left,
negated: left_neg,
},
&PatExprKind::Lit {
lit: right,
negated: right_neg,
},
) => left_neg == right_neg && left.node == right.node,
(PatExprKind::ConstBlock(left), PatExprKind::ConstBlock(right)) => self.eq_body(left.body, right.body),
(PatExprKind::Path(left), PatExprKind::Path(right)) => self.eq_qpath(left, right),
(PatExprKind::Lit { .. } | PatExprKind::ConstBlock(..) | PatExprKind::Path(..), _) => false,
}
}
/// Checks whether two patterns are the same. /// Checks whether two patterns are the same.
fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool { fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
match (&left.kind, &right.kind) { match (&left.kind, &right.kind) {
@ -507,11 +525,11 @@ impl HirEqInterExpr<'_, '_, '_> {
eq eq
}, },
(PatKind::Path(l), PatKind::Path(r)) => self.eq_qpath(l, r), (PatKind::Path(l), PatKind::Path(r)) => self.eq_qpath(l, r),
(&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r), (&PatKind::Lit(l), &PatKind::Lit(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::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)) => { (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_expr(a, b)) both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_pat_expr(a, b))
&& both(le.as_ref(), re.as_ref(), |a, b| self.eq_expr(a, b)) && both(le.as_ref(), re.as_ref(), |a, b| self.eq_pat_expr(a, b))
&& (li == ri) && (li == ri)
}, },
(&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re), (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
@ -1073,6 +1091,18 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
// self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s); // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
} }
pub fn hash_pat_expr(&mut self, lit: &PatExpr<'_>) {
std::mem::discriminant(&lit.kind).hash(&mut self.s);
match &lit.kind {
PatExprKind::Lit { lit, negated } => {
lit.node.hash(&mut self.s);
negated.hash(&mut self.s);
},
PatExprKind::ConstBlock(c) => self.hash_body(c.body),
PatExprKind::Path(qpath) => self.hash_qpath(qpath),
}
}
pub fn hash_pat(&mut self, pat: &Pat<'_>) { pub fn hash_pat(&mut self, pat: &Pat<'_>) {
std::mem::discriminant(&pat.kind).hash(&mut self.s); std::mem::discriminant(&pat.kind).hash(&mut self.s);
match pat.kind { match pat.kind {
@ -1084,7 +1114,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
} }
}, },
PatKind::Box(pat) | PatKind::Deref(pat) => self.hash_pat(pat), PatKind::Box(pat) | PatKind::Deref(pat) => self.hash_pat(pat),
PatKind::Lit(expr) => self.hash_expr(expr), PatKind::Lit(expr) => self.hash_pat_expr(expr),
PatKind::Or(pats) => { PatKind::Or(pats) => {
for pat in pats { for pat in pats {
self.hash_pat(pat); self.hash_pat(pat);
@ -1093,10 +1123,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
PatKind::Path(ref qpath) => self.hash_qpath(qpath), PatKind::Path(ref qpath) => self.hash_qpath(qpath),
PatKind::Range(s, e, i) => { PatKind::Range(s, e, i) => {
if let Some(s) = s { if let Some(s) = s {
self.hash_expr(s); self.hash_pat_expr(s);
} }
if let Some(e) = e { if let Some(e) = e {
self.hash_expr(e); self.hash_pat_expr(e);
} }
std::mem::discriminant(&i).hash(&mut self.s); std::mem::discriminant(&i).hash(&mut self.s);
}, },

View File

@ -31,7 +31,7 @@ if let StmtKind::Let(local) = stmt.kind
if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind
&& let ExprKind::Let(let_expr) = cond.kind && let ExprKind::Let(let_expr) = cond.kind
&& let PatKind::Lit(lit_expr) = let_expr.pat.kind && let PatKind::Lit(lit_expr) = let_expr.pat.kind
&& let ExprKind::Lit(ref lit) = lit_expr.kind && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
&& let LitKind::Bool(true) = lit.node && let LitKind::Bool(true) = lit.node
&& let ExprKind::Path(ref qpath) = let_expr.init.kind && let ExprKind::Path(ref qpath) = let_expr.init.kind
&& match_qpath(qpath, &["a"]) && match_qpath(qpath, &["a"])

View File

@ -77,7 +77,7 @@ if let Some(higher::While { condition: condition, body: body }) = higher::While:
} }
if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr) if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr)
&& let PatKind::Lit(lit_expr) = let_pat.kind && let PatKind::Lit(lit_expr) = let_pat.kind
&& let ExprKind::Lit(ref lit) = lit_expr.kind && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
&& let LitKind::Bool(true) = lit.node && let LitKind::Bool(true) = lit.node
&& let ExprKind::Path(ref qpath) = let_expr.kind && let ExprKind::Path(ref qpath) = let_expr.kind
&& match_qpath(qpath, &["a"]) && match_qpath(qpath, &["a"])

View File

@ -5,13 +5,13 @@ if let StmtKind::Let(local) = stmt.kind
&& let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node && let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node
&& arms.len() == 3 && arms.len() == 3
&& let PatKind::Lit(lit_expr) = arms[0].pat.kind && let PatKind::Lit(lit_expr) = arms[0].pat.kind
&& let ExprKind::Lit(ref lit1) = lit_expr.kind && let PatExprKind::Lit{ref lit1, negated } = lit_expr.kind
&& let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node && let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node
&& arms[0].guard.is_none() && arms[0].guard.is_none()
&& let ExprKind::Lit(ref lit2) = arms[0].body.kind && let ExprKind::Lit(ref lit2) = arms[0].body.kind
&& let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node && let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node
&& let PatKind::Lit(lit_expr1) = arms[1].pat.kind && let PatKind::Lit(lit_expr1) = arms[1].pat.kind
&& let ExprKind::Lit(ref lit3) = lit_expr1.kind && let PatExprKind::Lit{ref lit3, negated1 } = lit_expr1.kind
&& let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node && let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node
&& arms[1].guard.is_none() && arms[1].guard.is_none()
&& let ExprKind::Block(block, None) = arms[1].body.kind && let ExprKind::Block(block, None) = arms[1].body.kind

View File

@ -24,7 +24,7 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind
&& fields.len() == 1 && fields.len() == 1
&& fields[0].ident.as_str() == "field" && fields[0].ident.as_str() == "field"
&& let PatKind::Lit(lit_expr) = fields[0].pat.kind && let PatKind::Lit(lit_expr) = fields[0].pat.kind
&& let ExprKind::Lit(ref lit) = lit_expr.kind && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
&& let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
&& arm.guard.is_none() && arm.guard.is_none()
&& let ExprKind::Block(block, None) = arm.body.kind && let ExprKind::Block(block, None) = arm.body.kind
@ -37,7 +37,7 @@ if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind
&& match_qpath(qpath, &["TestTuple"]) && match_qpath(qpath, &["TestTuple"])
&& fields.len() == 1 && fields.len() == 1
&& let PatKind::Lit(lit_expr) = fields[0].kind && let PatKind::Lit(lit_expr) = fields[0].kind
&& let ExprKind::Lit(ref lit) = lit_expr.kind && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
&& let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
&& arm.guard.is_none() && arm.guard.is_none()
&& let ExprKind::Block(block, None) = arm.body.kind && let ExprKind::Block(block, None) = arm.body.kind

View File

@ -14,4 +14,4 @@ extern crate std;
fn main() ({ } as ()) fn main() ({ } as ())
fn foo((-(128 as i8) as i8)...(127 as i8): i8) ({ } as ()) fn foo(-128...127: i8) ({ } as ())