mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Exhaustively handle expressions in patterns
This commit is contained in:
parent
5df69191cb
commit
c9365dd09f
@ -102,17 +102,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
let kind = match &e.kind {
|
||||
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
|
||||
ExprKind::ConstBlock(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::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)),
|
||||
ExprKind::Repeat(expr, count) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let count = self.lower_array_length_to_const_arg(count);
|
||||
@ -153,18 +143,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let ohs = self.lower_expr(ohs);
|
||||
hir::ExprKind::Unary(op, ohs)
|
||||
}
|
||||
ExprKind::Lit(token_lit) => {
|
||||
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::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)),
|
||||
ExprKind::IncludedBytes(bytes) => {
|
||||
let lit = self.arena.alloc(respan(
|
||||
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 {
|
||||
match u {
|
||||
UnOp::Deref => hir::UnOp::Deref,
|
||||
|
@ -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>) {
|
||||
self.insert(field.span, field.hir_id, Node::PatField(field));
|
||||
self.with_parent(field.hir_id, |this| {
|
||||
|
@ -35,6 +35,7 @@
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![warn(unreachable_pub)]
|
||||
|
@ -1,9 +1,12 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir as hir;
|
||||
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 super::errors::{
|
||||
@ -367,24 +370,54 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// }
|
||||
// m!(S);
|
||||
// ```
|
||||
fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> {
|
||||
match &expr.kind {
|
||||
ExprKind::Lit(..)
|
||||
| ExprKind::ConstBlock(..)
|
||||
| ExprKind::IncludedBytes(..)
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => {}
|
||||
ExprKind::Path(..) if allow_paths => {}
|
||||
ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
|
||||
fn lower_expr_within_pat(
|
||||
&mut self,
|
||||
expr: &Expr,
|
||||
allow_paths: bool,
|
||||
) -> &'hir hir::PatExpr<'hir> {
|
||||
let err = |guar| hir::PatExprKind::Lit {
|
||||
lit: self.arena.alloc(respan(self.lower_span(expr.span), LitKind::Err(guar))),
|
||||
negated: false,
|
||||
};
|
||||
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 guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
|
||||
span: expr.span,
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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)]
|
||||
pub enum PatKind<'hir> {
|
||||
/// Represents a wildcard pattern (i.e., `_`).
|
||||
@ -1564,13 +1584,13 @@ pub enum PatKind<'hir> {
|
||||
Ref(&'hir Pat<'hir>, Mutability),
|
||||
|
||||
/// A literal.
|
||||
Lit(&'hir Expr<'hir>),
|
||||
Lit(&'hir PatExpr<'hir>),
|
||||
|
||||
/// A guard pattern (e.g., `x if guard(x)`).
|
||||
Guard(&'hir Pat<'hir>, &'hir Expr<'hir>),
|
||||
|
||||
/// 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)?]`.
|
||||
///
|
||||
@ -4144,6 +4164,10 @@ pub enum Node<'hir> {
|
||||
OpaqueTy(&'hir OpaqueTy<'hir>),
|
||||
Pat(&'hir Pat<'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>),
|
||||
Block(&'hir Block<'hir>),
|
||||
LetStmt(&'hir LetStmt<'hir>),
|
||||
@ -4200,6 +4224,7 @@ impl<'hir> Node<'hir> {
|
||||
| Node::Block(..)
|
||||
| Node::Ctor(..)
|
||||
| Node::Pat(..)
|
||||
| Node::PatExpr(..)
|
||||
| Node::Arm(..)
|
||||
| Node::LetStmt(..)
|
||||
| Node::Crate(..)
|
||||
|
@ -342,6 +342,9 @@ pub trait Visitor<'v>: Sized {
|
||||
fn visit_pat_field(&mut self, f: &'v PatField<'v>) -> Self::Result {
|
||||
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 {
|
||||
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));
|
||||
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, _) => {
|
||||
visit_opt!(visitor, visit_expr, lower_bound);
|
||||
visit_opt!(visitor, visit_expr, upper_bound);
|
||||
visit_opt!(visitor, visit_pat_expr, lower_bound);
|
||||
visit_opt!(visitor, visit_pat_expr, upper_bound);
|
||||
}
|
||||
PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
try_visit!(visitor.visit_id(constant.hir_id));
|
||||
visitor.visit_nested_body(constant.body)
|
||||
|
@ -2449,17 +2449,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
Ty::new_error(tcx, err)
|
||||
}
|
||||
hir::PatKind::Range(start, end, include_end) => {
|
||||
let expr_to_const = |expr: &'tcx hir::Expr<'tcx>| -> ty::Const<'tcx> {
|
||||
let (expr, neg) = match expr.kind {
|
||||
hir::ExprKind::Unary(hir::UnOp::Neg, negated) => {
|
||||
(negated, Some((expr.hir_id, expr.span)))
|
||||
}
|
||||
_ => (expr, None),
|
||||
};
|
||||
let (c, c_ty) = match &expr.kind {
|
||||
hir::ExprKind::Lit(lit) => {
|
||||
let expr_to_const = |expr: &'tcx hir::PatExpr<'tcx>| -> ty::Const<'tcx> {
|
||||
let (c, c_ty) = match expr.kind {
|
||||
hir::PatExprKind::Lit { lit, negated } => {
|
||||
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) {
|
||||
Ok(c) => c,
|
||||
Err(LitToConstError::Reported(err)) => {
|
||||
@ -2470,23 +2464,30 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
(ct, ty)
|
||||
}
|
||||
|
||||
hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
hir::PatExprKind::Path(hir::QPath::Resolved(
|
||||
_,
|
||||
path @ &hir::Path {
|
||||
res: Res::Def(DefKind::ConstParam, def_id),
|
||||
..
|
||||
},
|
||||
)) => {
|
||||
let _ = self.prohibit_generic_args(
|
||||
match self.prohibit_generic_args(
|
||||
path.segments.iter(),
|
||||
GenericsArgsErrExtend::Param(def_id),
|
||||
);
|
||||
let ty = tcx
|
||||
.type_of(def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic");
|
||||
let ct = self.lower_const_param(def_id, expr.hir_id);
|
||||
(ct, ty)
|
||||
) {
|
||||
Ok(()) => {
|
||||
let ty = tcx
|
||||
.type_of(def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic");
|
||||
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);
|
||||
if let Some((id, span)) = neg {
|
||||
self.record_ty(id, c_ty, span);
|
||||
}
|
||||
c
|
||||
};
|
||||
|
||||
|
@ -199,6 +199,7 @@ impl<'a> State<'a> {
|
||||
Node::OpaqueTy(o) => self.print_opaque_ty(o),
|
||||
Node::Pat(a) => self.print_pat(a),
|
||||
Node::PatField(a) => self.print_patfield(a),
|
||||
Node::PatExpr(a) => self.print_pat_expr(a),
|
||||
Node::Arm(a) => self.print_arm(a),
|
||||
Node::Infer(_) => self.word("_"),
|
||||
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<'_>) {
|
||||
self.maybe_print_comment(pat.span.lo());
|
||||
self.ann.pre(self, AnnNode::Pat(pat));
|
||||
@ -1966,17 +1980,17 @@ impl<'a> State<'a> {
|
||||
self.pclose();
|
||||
}
|
||||
}
|
||||
PatKind::Lit(e) => self.print_expr(e),
|
||||
PatKind::Lit(e) => self.print_pat_expr(e),
|
||||
PatKind::Range(begin, end, end_kind) => {
|
||||
if let Some(expr) = begin {
|
||||
self.print_expr(expr);
|
||||
self.print_pat_expr(expr);
|
||||
}
|
||||
match end_kind {
|
||||
RangeEnd::Included => self.word("..."),
|
||||
RangeEnd::Excluded => self.word(".."),
|
||||
}
|
||||
if let Some(expr) = end {
|
||||
self.print_expr(expr);
|
||||
self.print_pat_expr(expr);
|
||||
}
|
||||
}
|
||||
PatKind::Slice(before, slice, after) => {
|
||||
|
@ -430,6 +430,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
| hir::Node::AssocItemConstraint(_)
|
||||
| hir::Node::TraitRef(_)
|
||||
| hir::Node::PatField(_)
|
||||
| hir::Node::PatExpr(_)
|
||||
| hir::Node::LetStmt(_)
|
||||
| hir::Node::Synthetic
|
||||
| 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,
|
||||
block: &'tcx hir::ConstBlock,
|
||||
expected: Expectation<'tcx>,
|
||||
|
@ -1039,6 +1039,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
def_id,
|
||||
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),
|
||||
};
|
||||
|
||||
|
@ -170,6 +170,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
span,
|
||||
..
|
||||
})
|
||||
| hir::Node::PatExpr(&hir::PatExpr {
|
||||
kind: hir::PatExprKind::Path(QPath::TypeRelative(rcvr, segment)),
|
||||
span,
|
||||
..
|
||||
})
|
||||
| hir::Node::Pat(&hir::Pat {
|
||||
kind:
|
||||
hir::PatKind::Path(QPath::TypeRelative(rcvr, segment))
|
||||
|
@ -30,6 +30,7 @@ use tracing::{debug, instrument, trace};
|
||||
use ty::VariantDef;
|
||||
|
||||
use super::report_unexpected_variant_res;
|
||||
use crate::expectation::Expectation;
|
||||
use crate::gather_locals::DeclOrigin;
|
||||
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" {}`.
|
||||
//
|
||||
// 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,
|
||||
_ => AdjustMode::Peel,
|
||||
},
|
||||
@ -493,10 +494,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
(expected, def_br, max_ref_mutbl)
|
||||
}
|
||||
|
||||
fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
|
||||
let ty = match <.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(
|
||||
&self,
|
||||
span: Span,
|
||||
lt: &hir::Expr<'tcx>,
|
||||
lt: &hir::PatExpr<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
ti: &TopInfo<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
@ -507,7 +526,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// Byte string patterns behave the same way as array patterns
|
||||
// They can denote both statically and dynamically-sized byte arrays.
|
||||
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);
|
||||
if let ty::Ref(_, inner_ty, _) = *expected.kind()
|
||||
&& 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()
|
||||
&& 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 expected = self.resolve_vars_if_possible(expected);
|
||||
@ -565,15 +589,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
fn check_pat_range(
|
||||
&self,
|
||||
span: Span,
|
||||
lhs: Option<&'tcx hir::Expr<'tcx>>,
|
||||
rhs: Option<&'tcx hir::Expr<'tcx>>,
|
||||
lhs: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||
rhs: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||
expected: Ty<'tcx>,
|
||||
ti: &TopInfo<'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,
|
||||
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.
|
||||
// The early check here is not for correctness, but rather better
|
||||
// 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 {
|
||||
match pat_field.pat.kind {
|
||||
PatKind::Lit(expr)
|
||||
PatKind::Lit(_)
|
||||
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),
|
||||
) => {}
|
||||
_ => {
|
||||
|
@ -147,15 +147,16 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
|
||||
self.visit_body(body);
|
||||
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);
|
||||
}
|
||||
|
||||
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> {
|
||||
|
@ -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(..) => {
|
||||
self.visit_field_id(e.hir_id);
|
||||
}
|
||||
hir::ExprKind::ConstBlock(anon_const) => {
|
||||
self.visit_node_id(e.span, anon_const.hir_id);
|
||||
|
||||
let body = self.tcx().hir().body(anon_const.body);
|
||||
self.visit_body(body);
|
||||
hir::ExprKind::ConstBlock(ref anon_const) => {
|
||||
self.visit_const_block(e.span, anon_const);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -335,6 +339,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
|
||||
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>) {
|
||||
intravisit::walk_local(self, l);
|
||||
let var_ty = self.fcx.local_ty(l.span, l.hir_id);
|
||||
|
@ -938,6 +938,7 @@ impl<'hir> Map<'hir> {
|
||||
Node::OpaqueTy(op) => op.span,
|
||||
Node::Pat(pat) => pat.span,
|
||||
Node::PatField(field) => field.span,
|
||||
Node::PatExpr(lit) => lit.span,
|
||||
Node::Arm(arm) => arm.span,
|
||||
Node::Block(block) => block.span,
|
||||
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::Pat(_) => node_str("pat"),
|
||||
Node::PatField(_) => node_str("pattern field"),
|
||||
Node::PatExpr(_) => node_str("pattern literal"),
|
||||
Node::Param(_) => node_str("param"),
|
||||
Node::Arm(_) => node_str("arm"),
|
||||
Node::Block(_) => node_str("block"),
|
||||
|
@ -154,7 +154,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
|
||||
fn lower_pattern_range_endpoint(
|
||||
&mut self,
|
||||
expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
expr: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||
) -> Result<
|
||||
(Option<PatRangeBoundary<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>),
|
||||
ErrorGuaranteed,
|
||||
@ -200,13 +200,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
/// This is only called when the range is already known to be malformed.
|
||||
fn error_on_literal_overflow(
|
||||
&self,
|
||||
expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
expr: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
use hir::{ExprKind, UnOp};
|
||||
use rustc_ast::ast::LitKind;
|
||||
|
||||
let Some(mut expr) = expr else {
|
||||
let Some(expr) = expr else {
|
||||
return Ok(());
|
||||
};
|
||||
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
|
||||
// `eval_bits`, an overflowed value has already been wrapped around.
|
||||
// We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint.
|
||||
let mut negated = false;
|
||||
if let ExprKind::Unary(UnOp::Neg, sub_expr) = expr.kind {
|
||||
negated = true;
|
||||
expr = sub_expr;
|
||||
}
|
||||
let ExprKind::Lit(lit) = expr.kind else {
|
||||
let hir::PatExprKind::Lit { lit, negated } = expr.kind else {
|
||||
return Ok(());
|
||||
};
|
||||
let LitKind::Int(lit_val, _) = lit.node else {
|
||||
@ -248,8 +242,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
|
||||
fn lower_pattern_range(
|
||||
&mut self,
|
||||
lo_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
hi_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
lo_expr: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||
hi_expr: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||
end: RangeEnd,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
@ -662,25 +656,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
/// 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
|
||||
/// afterwards.
|
||||
fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
|
||||
let (lit, neg) = match expr.kind {
|
||||
hir::ExprKind::Path(ref qpath) => {
|
||||
fn lower_lit(&mut self, expr: &'tcx hir::PatExpr<'tcx>) -> PatKind<'tcx> {
|
||||
let (lit, neg) = match &expr.kind {
|
||||
hir::PatExprKind::Path(qpath) => {
|
||||
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);
|
||||
}
|
||||
hir::ExprKind::Lit(ref lit) => (lit, false),
|
||||
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),
|
||||
hir::PatExprKind::Lit { lit, negated } => (lit, *negated),
|
||||
};
|
||||
|
||||
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 };
|
||||
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,
|
||||
|
@ -3,8 +3,11 @@ use clippy_utils::numeric_literal;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{Visitor, walk_expr, walk_stmt};
|
||||
use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind, StructTailExpr};
|
||||
use rustc_hir::intravisit::{Visitor, walk_expr, walk_pat, walk_stmt};
|
||||
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_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty};
|
||||
@ -219,6 +222,22 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> {
|
||||
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<'_>) {
|
||||
match stmt.kind {
|
||||
// we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric`
|
||||
|
@ -8,8 +8,8 @@ use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::{DefId, DefIdSet};
|
||||
use rustc_hir::{
|
||||
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
|
||||
ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatKind, PathSegment, PrimTy, QPath,
|
||||
TraitItemRef, TyKind,
|
||||
ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy,
|
||||
QPath, TraitItemRef, TyKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
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
|
||||
&& match lt.pat.kind {
|
||||
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,
|
||||
}
|
||||
&& !expr.span.from_expansion()
|
||||
|
@ -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::ast::RangeLimits;
|
||||
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_middle::ty;
|
||||
use rustc_session::impl_lint_pass;
|
||||
@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
|
||||
{
|
||||
let arg = peel_ref_operators(cx, arg);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
&& let ExprKind::Lit(end_lit) = &end.kind
|
||||
{
|
||||
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,
|
||||
}
|
||||
check_lit_range(start_lit, end_lit)
|
||||
} else {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use clippy_utils::source::SpanRangeExt;
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
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_middle::lint::in_external_macro;
|
||||
use rustc_session::declare_lint_pass;
|
||||
@ -38,14 +38,13 @@ declare_clippy_lint! {
|
||||
}
|
||||
declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]);
|
||||
|
||||
fn expr_as_i128(expr: &Expr<'_>) -> Option<i128> {
|
||||
if let ExprKind::Unary(UnOp::Neg, expr) = expr.kind {
|
||||
expr_as_i128(expr).map(|num| -num)
|
||||
} else if let ExprKind::Lit(lit) = expr.kind
|
||||
fn expr_as_i128(expr: &PatExpr<'_>) -> Option<i128> {
|
||||
if let PatExprKind::Lit { lit, negated } = expr.kind
|
||||
&& let LitKind::Int(num, _) = lit.node
|
||||
{
|
||||
// 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 {
|
||||
None
|
||||
}
|
||||
@ -58,7 +57,7 @@ struct Num {
|
||||
}
|
||||
|
||||
impl Num {
|
||||
fn new(expr: &Expr<'_>) -> Option<Self> {
|
||||
fn new(expr: &PatExpr<'_>) -> Option<Self> {
|
||||
Some(Self {
|
||||
val: expr_as_i128(expr)?,
|
||||
span: expr.span,
|
||||
|
@ -4,7 +4,7 @@ use clippy_utils::source::{expr_block, snippet};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Arm, Expr, ExprKind, PatKind};
|
||||
use rustc_hir::{Arm, Expr, PatExprKind, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
|
||||
@ -22,7 +22,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
|
||||
if arms.len() == 2 {
|
||||
// no guards
|
||||
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 {
|
||||
LitKind::Bool(true) => Some((arms[0].body, arms[1].body)),
|
||||
LitKind::Bool(false) => Some((arms[1].body, arms[0].body)),
|
||||
|
@ -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, 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::{LateContext, LintContext};
|
||||
use rustc_middle::ty;
|
||||
@ -313,7 +313,7 @@ impl<'a> NormalizedPat<'a> {
|
||||
},
|
||||
PatKind::Lit(e) => match &e.kind {
|
||||
// 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::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes),
|
||||
LitKind::Byte(val) => Self::LitInt(val.into()),
|
||||
@ -330,7 +330,7 @@ impl<'a> NormalizedPat<'a> {
|
||||
let start = match start {
|
||||
None => 0,
|
||||
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::Char(val) => val.into(),
|
||||
LitKind::Byte(val) => val.into(),
|
||||
@ -342,7 +342,7 @@ impl<'a> NormalizedPat<'a> {
|
||||
let (end, bounds) = match end {
|
||||
None => (u128::MAX, RangeEnd::Included),
|
||||
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::Char(val) => (val.into(), bounds),
|
||||
LitKind::Byte(val) => (val.into(), bounds),
|
||||
|
@ -5,7 +5,7 @@ use clippy_utils::ty::is_type_lang_item;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
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_middle::ty;
|
||||
use rustc_span::Span;
|
||||
@ -85,8 +85,8 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(
|
||||
};
|
||||
|
||||
for arm in arms {
|
||||
if let PatKind::Lit(Expr {
|
||||
kind: ExprKind::Lit(lit),
|
||||
if let PatKind::Lit(PatExpr {
|
||||
kind: PatExprKind::Lit { lit, negated: false },
|
||||
..
|
||||
}) = arm.pat.kind
|
||||
&& let LitKind::Str(symbol, _) = lit.node
|
||||
|
@ -8,7 +8,7 @@ use clippy_utils::{
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
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_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`
|
||||
Node::Item(item) => {
|
||||
if let ItemKind::Fn{ .. } = item.kind {
|
||||
if let ItemKind::Fn { .. } = item.kind {
|
||||
let output = cx
|
||||
.tcx
|
||||
.fn_sig(item.owner_id)
|
||||
@ -189,8 +189,12 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
|
||||
});
|
||||
},
|
||||
// Example: `5 => 5`
|
||||
(PatKind::Lit(pat_lit_expr), ExprKind::Lit(expr_spanned)) => {
|
||||
if let ExprKind::Lit(pat_spanned) = &pat_lit_expr.kind {
|
||||
(PatKind::Lit(pat_expr_expr), ExprKind::Lit(expr_spanned)) => {
|
||||
if let PatExprKind::Lit {
|
||||
lit: pat_spanned,
|
||||
negated: false,
|
||||
} = &pat_expr_expr.kind
|
||||
{
|
||||
return pat_spanned.node == expr_spanned.node;
|
||||
}
|
||||
},
|
||||
|
@ -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 PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
|
||||
let lhs_const = if let Some(lhs) = lhs {
|
||||
ConstEvalCtxt::new(cx).eval(lhs)?
|
||||
ConstEvalCtxt::new(cx).eval_pat_expr(lhs)?
|
||||
} else {
|
||||
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))?
|
||||
};
|
||||
let rhs_const = if let Some(rhs) = rhs {
|
||||
ConstEvalCtxt::new(cx).eval(rhs)?
|
||||
ConstEvalCtxt::new(cx).eval_pat_expr(rhs)?
|
||||
} else {
|
||||
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))?
|
||||
@ -58,7 +58,9 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
|
||||
}
|
||||
|
||||
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 {
|
||||
span: pat.span,
|
||||
node: (value, EndBound::Included(value)),
|
||||
|
@ -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, PatKind, QPath, UnOp};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp, PatExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, GenericArgKind, Ty};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
@ -75,7 +75,7 @@ fn find_match_true<'tcx>(
|
||||
message: &'static str,
|
||||
) {
|
||||
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 mut applicability = Applicability::MachineApplicable;
|
||||
|
@ -9,7 +9,7 @@ use rustc_arena::DroplessArena;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
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_middle::ty::{self, AdtDef, TyCtxt, TypeckResults, VariantDef};
|
||||
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.
|
||||
let pat_ref_count = match pat.kind {
|
||||
// string literals are already a reference.
|
||||
PatKind::Lit(Expr {
|
||||
kind: ExprKind::Lit(lit),
|
||||
PatKind::Lit(PatExpr {
|
||||
kind: PatExprKind::Lit { lit, negated: false },
|
||||
..
|
||||
}) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1,
|
||||
_ => pat_ref_count,
|
||||
|
@ -11,7 +11,7 @@ use clippy_utils::visitors::{Descend, for_each_expr};
|
||||
use itertools::Itertools;
|
||||
use rustc_ast::{BinOpKind, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, PatKind};
|
||||
use rustc_hir::{Expr, ExprKind, PatExprKind, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::impl_lint_pass;
|
||||
@ -171,7 +171,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
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 {
|
||||
set_char_spans.push(lit.span);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use rustc_ast::ast::{LitFloatType, LitKind};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::{
|
||||
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_session::declare_lint_pass;
|
||||
@ -643,6 +643,27 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
||||
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<'_>>) {
|
||||
let kind = |kind| chain!(self, "let PatKind::{kind} = {pat}.kind");
|
||||
macro_rules! kind {
|
||||
@ -721,13 +742,13 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
||||
PatKind::Lit(lit_expr) => {
|
||||
bind!(self, lit_expr);
|
||||
kind!("Lit({lit_expr})");
|
||||
self.expr(lit_expr);
|
||||
self.pat_expr(lit_expr);
|
||||
},
|
||||
PatKind::Range(start, end, end_kind) => {
|
||||
opt_bind!(self, start, end);
|
||||
kind!("Range({start}, {end}, RangeEnd::{end_kind:?})");
|
||||
start.if_some(|e| self.expr(e));
|
||||
end.if_some(|e| self.expr(e));
|
||||
start.if_some(|e| self.pat_expr(e));
|
||||
end.if_some(|e| self.pat_expr(e));
|
||||
},
|
||||
PatKind::Slice(start, middle, end) => {
|
||||
bind!(self, start, end);
|
||||
|
@ -4,7 +4,6 @@
|
||||
//! executable MIR bodies, so we have to do this instead.
|
||||
#![allow(clippy::float_cmp)]
|
||||
|
||||
use crate::macros::HirNode;
|
||||
use crate::source::{SpanRangeExt, walk_span_to_context};
|
||||
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_data_structures::sync::Lrc;
|
||||
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_lint::LateContext;
|
||||
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.
|
||||
fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
match e.kind {
|
||||
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value),
|
||||
ExprKind::DropTemps(e) => self.expr(e),
|
||||
ExprKind::Path(ref qpath) => {
|
||||
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::Path(ref qpath) => self.qpath(qpath, e.hir_id),
|
||||
ExprKind::Block(block, _) => self.block(block),
|
||||
ExprKind::Lit(lit) => {
|
||||
if is_direct_expn_of(e.span, "cfg").is_some() {
|
||||
|
@ -9,8 +9,8 @@ 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, LifetimeName,
|
||||
Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty,
|
||||
TyKind,
|
||||
Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr,
|
||||
TraitBoundModifiers, Ty, TyKind,
|
||||
};
|
||||
use rustc_lexer::{TokenKind, tokenize};
|
||||
use rustc_lint::LateContext;
|
||||
@ -489,6 +489,24 @@ impl HirEqInterExpr<'_, '_, '_> {
|
||||
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.
|
||||
fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
|
||||
match (&left.kind, &right.kind) {
|
||||
@ -507,11 +525,11 @@ impl HirEqInterExpr<'_, '_, '_> {
|
||||
eq
|
||||
},
|
||||
(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::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(le.as_ref(), re.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_pat_expr(a, b))
|
||||
&& (li == ri)
|
||||
},
|
||||
(&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);
|
||||
}
|
||||
|
||||
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<'_>) {
|
||||
std::mem::discriminant(&pat.kind).hash(&mut self.s);
|
||||
match pat.kind {
|
||||
@ -1084,7 +1114,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||
}
|
||||
},
|
||||
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) => {
|
||||
for pat in pats {
|
||||
self.hash_pat(pat);
|
||||
@ -1093,10 +1123,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||
PatKind::Path(ref qpath) => self.hash_qpath(qpath),
|
||||
PatKind::Range(s, e, i) => {
|
||||
if let Some(s) = s {
|
||||
self.hash_expr(s);
|
||||
self.hash_pat_expr(s);
|
||||
}
|
||||
if let Some(e) = e {
|
||||
self.hash_expr(e);
|
||||
self.hash_pat_expr(e);
|
||||
}
|
||||
std::mem::discriminant(&i).hash(&mut self.s);
|
||||
},
|
||||
|
@ -31,7 +31,7 @@ if let StmtKind::Let(local) = stmt.kind
|
||||
if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind
|
||||
&& let ExprKind::Let(let_expr) = cond.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 ExprKind::Path(ref qpath) = let_expr.init.kind
|
||||
&& match_qpath(qpath, &["a"])
|
||||
|
@ -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)
|
||||
&& 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 ExprKind::Path(ref qpath) = let_expr.kind
|
||||
&& match_qpath(qpath, &["a"])
|
||||
|
@ -5,13 +5,13 @@ if let StmtKind::Let(local) = stmt.kind
|
||||
&& let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node
|
||||
&& arms.len() == 3
|
||||
&& 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
|
||||
&& arms[0].guard.is_none()
|
||||
&& let ExprKind::Lit(ref lit2) = arms[0].body.kind
|
||||
&& let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node
|
||||
&& 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
|
||||
&& arms[1].guard.is_none()
|
||||
&& let ExprKind::Block(block, None) = arms[1].body.kind
|
||||
|
@ -24,7 +24,7 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind
|
||||
&& fields.len() == 1
|
||||
&& fields[0].ident.as_str() == "field"
|
||||
&& 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
|
||||
&& arm.guard.is_none()
|
||||
&& 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"])
|
||||
&& fields.len() == 1
|
||||
&& 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
|
||||
&& arm.guard.is_none()
|
||||
&& let ExprKind::Block(block, None) = arm.body.kind
|
||||
|
@ -14,4 +14,4 @@ extern crate std;
|
||||
|
||||
fn main() ({ } as ())
|
||||
|
||||
fn foo((-(128 as i8) as i8)...(127 as i8): i8) ({ } as ())
|
||||
fn foo(-128...127: i8) ({ } as ())
|
||||
|
Loading…
Reference in New Issue
Block a user