mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
Rollup merge of #134228 - oli-obk:pat-lit-path, r=compiler-errors
Exhaustively handle expressions in patterns We currently have this invariant in HIR that a `PatKind::Lit` or a `PatKind::Range` only contains * `ExprKind::Lit` * `ExprKind::UnOp(Neg, ExprKind::Lit)` * `ExprKind::Path` * `ExprKind::ConstBlock` So I made `PatKind::Lit` and `PatKind::Range` stop containing `Expr`, and instead created a `PatLit` type whose `kind` enum only contains those variants. The only place code got more complicated was in clippy, as it couldn't share as much anymore with `Expr` handling It may be interesting on merging `ExprKind::{Path,Lit,ConstBlock}` in the future and using the same `PatLit` type (under a new name). Then it should also be easier to eliminate any and all `UnOp(Neg, Lit) | Lit` matching that we have across the compiler. Some day we should fold the negation into the literal itself and just store it on the numeric literals
This commit is contained in:
commit
f92a5ed5b4
@ -623,7 +623,7 @@ impl Pat {
|
||||
PatKind::Wild
|
||||
| PatKind::Rest
|
||||
| PatKind::Never
|
||||
| PatKind::Lit(_)
|
||||
| PatKind::Expr(_)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Ident(..)
|
||||
| PatKind::Path(..)
|
||||
@ -801,8 +801,8 @@ pub enum PatKind {
|
||||
/// A reference pattern (e.g., `&mut (a, b)`).
|
||||
Ref(P<Pat>, Mutability),
|
||||
|
||||
/// A literal.
|
||||
Lit(P<Expr>),
|
||||
/// A literal, const block or path.
|
||||
Expr(P<Expr>),
|
||||
|
||||
/// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
|
||||
Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>),
|
||||
|
@ -1512,7 +1512,7 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
|
||||
vis.visit_ident(ident);
|
||||
visit_opt(sub, |sub| vis.visit_pat(sub));
|
||||
}
|
||||
PatKind::Lit(e) => vis.visit_expr(e),
|
||||
PatKind::Expr(e) => vis.visit_expr(e),
|
||||
PatKind::TupleStruct(qself, path, elems) => {
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
|
@ -680,7 +680,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
visit_opt!(visitor, visit_pat, optional_subpattern);
|
||||
}
|
||||
PatKind::Lit(expression) => try_visit!(visitor.visit_expr(expression)),
|
||||
PatKind::Expr(expression) => try_visit!(visitor.visit_expr(expression)),
|
||||
PatKind::Range(lower_bound, upper_bound, _end) => {
|
||||
visit_opt!(visitor, visit_expr, lower_bound);
|
||||
visit_opt!(visitor, visit_expr, upper_bound);
|
||||
|
@ -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::{
|
||||
@ -35,8 +38,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
lower_sub,
|
||||
);
|
||||
}
|
||||
PatKind::Lit(e) => {
|
||||
break hir::PatKind::Lit(self.lower_expr_within_pat(e, false));
|
||||
PatKind::Expr(e) => {
|
||||
break hir::PatKind::Expr(self.lower_expr_within_pat(e, false));
|
||||
}
|
||||
PatKind::TupleStruct(qself, path, pats) => {
|
||||
let qpath = self.lower_qpath(
|
||||
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1701,7 +1701,7 @@ impl<'a> State<'a> {
|
||||
self.print_pat(inner);
|
||||
}
|
||||
}
|
||||
PatKind::Lit(e) => self.print_expr(e, FixupContext::default()),
|
||||
PatKind::Expr(e) => self.print_expr(e, FixupContext::default()),
|
||||
PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => {
|
||||
if let Some(e) = begin {
|
||||
self.print_expr(e, FixupContext::default());
|
||||
|
@ -522,7 +522,7 @@ impl MacResult for MacEager {
|
||||
return Some(P(ast::Pat {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: e.span,
|
||||
kind: PatKind::Lit(e),
|
||||
kind: PatKind::Expr(e),
|
||||
tokens: None,
|
||||
}));
|
||||
}
|
||||
|
@ -486,7 +486,7 @@ impl<'a> ExtCtxt<'a> {
|
||||
self.pat(span, PatKind::Wild)
|
||||
}
|
||||
pub fn pat_lit(&self, span: Span, expr: P<ast::Expr>) -> P<ast::Pat> {
|
||||
self.pat(span, PatKind::Lit(expr))
|
||||
self.pat(span, PatKind::Expr(expr))
|
||||
}
|
||||
pub fn pat_ident(&self, span: Span, ident: Ident) -> P<ast::Pat> {
|
||||
self.pat_ident_binding_mode(span, ident, ast::BindingMode::NONE)
|
||||
|
@ -1386,7 +1386,7 @@ impl<'hir> Pat<'hir> {
|
||||
|
||||
use PatKind::*;
|
||||
match self.kind {
|
||||
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
|
||||
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
|
||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it),
|
||||
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
|
||||
@ -1413,7 +1413,7 @@ impl<'hir> Pat<'hir> {
|
||||
|
||||
use PatKind::*;
|
||||
match self.kind {
|
||||
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
|
||||
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
|
||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
|
||||
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
|
||||
@ -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., `_`).
|
||||
@ -1563,14 +1583,14 @@ pub enum PatKind<'hir> {
|
||||
/// A reference pattern (e.g., `&mut (a, b)`).
|
||||
Ref(&'hir Pat<'hir>, Mutability),
|
||||
|
||||
/// A literal.
|
||||
Lit(&'hir Expr<'hir>),
|
||||
/// A literal, const block or path.
|
||||
Expr(&'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::Expr(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)
|
||||
|
@ -704,7 +704,7 @@ fn resolve_local<'tcx>(
|
||||
| PatKind::Wild
|
||||
| PatKind::Never
|
||||
| PatKind::Path(_)
|
||||
| PatKind::Lit(_)
|
||||
| PatKind::Expr(_)
|
||||
| PatKind::Range(_, _, _)
|
||||
| PatKind::Err(_) => false,
|
||||
}
|
||||
|
@ -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::Expr(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(_)
|
||||
@ -484,7 +485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
| hir::PatKind::Box(_)
|
||||
| hir::PatKind::Ref(_, _)
|
||||
| hir::PatKind::Deref(_)
|
||||
| hir::PatKind::Lit(_)
|
||||
| hir::PatKind::Expr(_)
|
||||
| hir::PatKind::Range(_, _, _)
|
||||
| hir::PatKind::Slice(_, _, _)
|
||||
| hir::PatKind::Err(_) => true,
|
||||
@ -837,7 +838,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// We always require that the type provided as the value for
|
||||
// a type parameter outlives the moment of instantiation.
|
||||
let args = self.typeck_results.borrow().node_args(expr.hir_id);
|
||||
self.add_wf_bounds(args, expr);
|
||||
self.add_wf_bounds(args, expr.span);
|
||||
|
||||
ty
|
||||
}
|
||||
@ -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>,
|
||||
|
@ -595,7 +595,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||
let place_ty = place.place.ty();
|
||||
needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span);
|
||||
}
|
||||
PatKind::Lit(_) | PatKind::Range(..) => {
|
||||
PatKind::Expr(_) | PatKind::Range(..) => {
|
||||
// If the PatKind is a Lit or a Range then we want
|
||||
// to borrow discr.
|
||||
needs_to_be_read = true;
|
||||
@ -1803,7 +1803,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||
|
||||
PatKind::Path(_)
|
||||
| PatKind::Binding(.., None)
|
||||
| PatKind::Lit(..)
|
||||
| PatKind::Expr(..)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Never
|
||||
| PatKind::Wild
|
||||
|
@ -577,11 +577,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
/// Registers obligations that all `args` are well-formed.
|
||||
pub(crate) fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, expr: &hir::Expr<'_>) {
|
||||
pub(crate) fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, span: Span) {
|
||||
for arg in args.iter().filter(|arg| {
|
||||
matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
|
||||
}) {
|
||||
self.register_wf_obligation(arg, expr.span, ObligationCauseCode::WellFormed(None));
|
||||
self.register_wf_obligation(arg, span, ObligationCauseCode::WellFormed(None));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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),
|
||||
};
|
||||
|
||||
|
@ -611,7 +611,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||
|
||||
// this is a projection from a trait reference, so we have to
|
||||
// make sure that the trait reference inputs are well-formed.
|
||||
self.add_wf_bounds(all_args, self.call_expr);
|
||||
self.add_wf_bounds(all_args, self.call_expr.span);
|
||||
|
||||
// the function type must also be well-formed (this is not
|
||||
// implied by the args being well-formed because of inherent
|
||||
|
@ -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};
|
||||
|
||||
@ -270,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
PatKind::Wild | PatKind::Err(_) => expected,
|
||||
// We allow any type here; we ensure that the type is uninhabited during match checking.
|
||||
PatKind::Never => expected,
|
||||
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
|
||||
PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
|
||||
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
|
||||
PatKind::Binding(ba, var_id, ident, sub) => {
|
||||
self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
|
||||
@ -279,7 +280,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
|
||||
}
|
||||
PatKind::Path(ref qpath) => {
|
||||
self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti)
|
||||
self.check_pat_path(pat.hir_id, pat.span, qpath, path_res.unwrap(), expected, ti)
|
||||
}
|
||||
PatKind::Struct(ref qpath, fields, has_rest_pat) => {
|
||||
self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
|
||||
@ -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::Expr(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
|
||||
@ -919,7 +943,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
| PatKind::Box(..)
|
||||
| PatKind::Deref(_)
|
||||
| PatKind::Ref(..)
|
||||
| PatKind::Lit(..)
|
||||
| PatKind::Expr(..)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Err(_) => break 'block None,
|
||||
},
|
||||
@ -1053,7 +1077,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
fn check_pat_path(
|
||||
&self,
|
||||
pat: &Pat<'tcx>,
|
||||
hir_id: HirId,
|
||||
span: Span,
|
||||
qpath: &hir::QPath<'_>,
|
||||
path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
|
||||
expected: Ty<'tcx>,
|
||||
@ -1072,8 +1097,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
|
||||
let expected = "unit struct, unit variant or constant";
|
||||
let e =
|
||||
report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0533, expected);
|
||||
let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected);
|
||||
return Ty::new_error(tcx, e);
|
||||
}
|
||||
Res::SelfCtor(def_id) => {
|
||||
@ -1088,7 +1112,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
res,
|
||||
None,
|
||||
qpath,
|
||||
pat.span,
|
||||
span,
|
||||
E0533,
|
||||
"unit struct",
|
||||
);
|
||||
@ -1107,11 +1131,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
// Type-check the path.
|
||||
let (pat_ty, pat_res) =
|
||||
self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id);
|
||||
self.instantiate_value_path(segments, opt_ty, res, span, span, hir_id);
|
||||
if let Err(err) =
|
||||
self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty)
|
||||
self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, pat_ty)
|
||||
{
|
||||
self.emit_bad_pat_path(err, pat, res, pat_res, pat_ty, segments);
|
||||
self.emit_bad_pat_path(err, hir_id, span, res, pat_res, pat_ty, segments);
|
||||
}
|
||||
pat_ty
|
||||
}
|
||||
@ -1154,13 +1178,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
fn emit_bad_pat_path(
|
||||
&self,
|
||||
mut e: Diag<'_>,
|
||||
pat: &hir::Pat<'tcx>,
|
||||
hir_id: HirId,
|
||||
pat_span: Span,
|
||||
res: Res,
|
||||
pat_res: Res,
|
||||
pat_ty: Ty<'tcx>,
|
||||
segments: &'tcx [hir::PathSegment<'tcx>],
|
||||
) {
|
||||
let pat_span = pat.span;
|
||||
if let Some(span) = self.tcx.hir().res_span(pat_res) {
|
||||
e.span_label(span, format!("{} defined here", res.descr()));
|
||||
if let [hir::PathSegment { ident, .. }] = &*segments {
|
||||
@ -1173,7 +1197,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
res.descr(),
|
||||
),
|
||||
);
|
||||
match self.tcx.parent_hir_node(pat.hir_id) {
|
||||
match self.tcx.parent_hir_node(hir_id) {
|
||||
hir::Node::PatField(..) => {
|
||||
e.span_suggestion_verbose(
|
||||
ident.span.shrink_to_hi(),
|
||||
@ -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::Expr(_)
|
||||
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);
|
||||
|
@ -1220,7 +1220,7 @@ impl EarlyLintPass for UnusedParens {
|
||||
// Do not lint on `(..)` as that will result in the other arms being useless.
|
||||
Paren(_)
|
||||
// The other cases do not contain sub-patterns.
|
||||
| Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {},
|
||||
| Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {},
|
||||
// These are list-like patterns; parens can always be removed.
|
||||
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
|
||||
self.check_unused_parens_pat(cx, p, false, false, keep_space);
|
||||
|
@ -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,
|
||||
@ -330,7 +324,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
|
||||
hir::PatKind::Never => PatKind::Never,
|
||||
|
||||
hir::PatKind::Lit(value) => self.lower_lit(value),
|
||||
hir::PatKind::Expr(value) => self.lower_lit(value),
|
||||
|
||||
hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
|
||||
let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
|
||||
@ -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,
|
||||
|
@ -656,14 +656,14 @@ impl<'a> Parser<'a> {
|
||||
fn visit_pat(&mut self, p: &'a Pat) -> Self::Result {
|
||||
match &p.kind {
|
||||
// Base expression
|
||||
PatKind::Err(_) | PatKind::Lit(_) => {
|
||||
PatKind::Err(_) | PatKind::Expr(_) => {
|
||||
self.maybe_add_suggestions_then_emit(p.span, p.span, false)
|
||||
}
|
||||
|
||||
// Sub-patterns
|
||||
// FIXME: this doesn't work with recursive subpats (`&mut &mut <err>`)
|
||||
PatKind::Box(subpat) | PatKind::Ref(subpat, _)
|
||||
if matches!(subpat.kind, PatKind::Err(_) | PatKind::Lit(_)) =>
|
||||
if matches!(subpat.kind, PatKind::Err(_) | PatKind::Expr(_)) =>
|
||||
{
|
||||
self.maybe_add_suggestions_then_emit(subpat.span, p.span, false)
|
||||
}
|
||||
@ -766,7 +766,7 @@ impl<'a> Parser<'a> {
|
||||
if let Some(re) = self.parse_range_end() {
|
||||
self.parse_pat_range_begin_with(const_expr, re)?
|
||||
} else {
|
||||
PatKind::Lit(const_expr)
|
||||
PatKind::Expr(const_expr)
|
||||
}
|
||||
} else if self.is_builtin() {
|
||||
self.parse_pat_builtin()?
|
||||
@ -833,7 +833,7 @@ impl<'a> Parser<'a> {
|
||||
.struct_span_err(self_.token.span, msg)
|
||||
.with_span_label(self_.token.span, format!("expected {expected}"))
|
||||
});
|
||||
PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit)))
|
||||
PatKind::Expr(self.mk_expr(lo, ExprKind::Lit(lit)))
|
||||
} else {
|
||||
// Try to parse everything else as literal with optional minus
|
||||
match self.parse_literal_maybe_minus() {
|
||||
@ -845,7 +845,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
match self.parse_range_end() {
|
||||
Some(form) => self.parse_pat_range_begin_with(begin, form)?,
|
||||
None => PatKind::Lit(begin),
|
||||
None => PatKind::Expr(begin),
|
||||
}
|
||||
}
|
||||
Err(err) => return self.fatal_unexpected_non_pat(err, expected),
|
||||
@ -989,7 +989,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
match &pat.kind {
|
||||
// recover ranges with parentheses around the `(start)..`
|
||||
PatKind::Lit(begin)
|
||||
PatKind::Expr(begin)
|
||||
if self.may_recover()
|
||||
&& let Some(form) = self.parse_range_end() =>
|
||||
{
|
||||
|
@ -304,7 +304,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
||||
Box,
|
||||
Deref,
|
||||
Ref,
|
||||
Lit,
|
||||
Expr,
|
||||
Guard,
|
||||
Range,
|
||||
Slice,
|
||||
@ -587,7 +587,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
||||
Box,
|
||||
Deref,
|
||||
Ref,
|
||||
Lit,
|
||||
Expr,
|
||||
Range,
|
||||
Slice,
|
||||
Rest,
|
||||
|
@ -314,9 +314,9 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
|
||||
PatKind::Box(p) => return name_from_pat(p),
|
||||
PatKind::Deref(p) => format!("deref!({})", name_from_pat(p)),
|
||||
PatKind::Ref(p, _) => return name_from_pat(p),
|
||||
PatKind::Lit(..) => {
|
||||
PatKind::Expr(..) => {
|
||||
warn!(
|
||||
"tried to get argument name from PatKind::Lit, which is silly in function arguments"
|
||||
"tried to get argument name from PatKind::Expr, which is silly in function arguments"
|
||||
);
|
||||
return Symbol::intern("()");
|
||||
}
|
||||
|
@ -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::Expr(&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`
|
||||
|
@ -56,7 +56,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
|
||||
PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
|
||||
PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
|
||||
PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x),
|
||||
PatKind::Path(_) | PatKind::Lit(_) => true,
|
||||
PatKind::Path(_) | PatKind::Expr(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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::Expr(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,
|
||||
@ -90,7 +89,7 @@ impl LateLintPass<'_> for ManualRangePatterns {
|
||||
let mut ranges_found = Vec::new();
|
||||
|
||||
for pat in pats {
|
||||
if let PatKind::Lit(lit) = pat.kind
|
||||
if let PatKind::Expr(lit) = pat.kind
|
||||
&& let Some(num) = Num::new(lit)
|
||||
{
|
||||
numbers_found.insert(num.val);
|
||||
|
@ -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;
|
||||
|
||||
@ -21,8 +21,8 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
|
||||
move |diag| {
|
||||
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 {
|
||||
let exprs = if let PatKind::Expr(arm_bool) = arms[0].pat.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, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExprKind, PatKind, RangeEnd};
|
||||
use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::ty;
|
||||
@ -311,9 +311,9 @@ impl<'a> NormalizedPat<'a> {
|
||||
);
|
||||
Self::Tuple(None, pats)
|
||||
},
|
||||
PatKind::Lit(e) => match &e.kind {
|
||||
PatKind::Expr(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::Expr(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::Expr(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))?
|
||||
@ -57,8 +57,10 @@ 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)?;
|
||||
if let PatKind::Expr(value) = pat.kind {
|
||||
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, PatExprKind, PatKind, QPath, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, GenericArgKind, Ty};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
@ -74,8 +74,8 @@ fn find_match_true<'tcx>(
|
||||
span: Span,
|
||||
message: &'static str,
|
||||
) {
|
||||
if let PatKind::Lit(lit) = pat.kind
|
||||
&& let ExprKind::Lit(lit) = lit.kind
|
||||
if let PatKind::Expr(lit) = pat.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, PatExpr, PatExprKind, PatKind, QPath, StmtKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, AdtDef, TyCtxt, TypeckResults, VariantDef};
|
||||
use rustc_span::{Span, sym};
|
||||
@ -114,7 +114,7 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
|
||||
}
|
||||
|
||||
let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat);
|
||||
let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind
|
||||
let (msg, sugg) = if let PatKind::Path(_) | PatKind::Expr(_) = pat.kind
|
||||
&& let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex))
|
||||
&& let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
|
||||
&& let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
|
||||
@ -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::Expr(PatExpr {
|
||||
kind: PatExprKind::Lit { lit, negated: false },
|
||||
..
|
||||
}) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1,
|
||||
_ => pat_ref_count,
|
||||
@ -384,7 +384,7 @@ impl<'a> PatState<'a> {
|
||||
|
||||
PatKind::Wild
|
||||
| PatKind::Binding(_, _, _, None)
|
||||
| PatKind::Lit(_)
|
||||
| PatKind::Expr(_)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Path(_)
|
||||
| PatKind::Never
|
||||
|
@ -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::Expr(expr) if let PatExprKind::Lit { lit, negated: false } = expr.kind => {
|
||||
if let LitKind::Char(_) = lit.node {
|
||||
set_char_spans.push(lit.span);
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ impl EarlyLintPass for UnnestedOrPatterns {
|
||||
}
|
||||
|
||||
fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {
|
||||
if let Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) = pat.kind {
|
||||
if let Ident(.., None) | Expr(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) = pat.kind {
|
||||
// This is a leaf pattern, so cloning is unprofitable.
|
||||
return;
|
||||
}
|
||||
@ -228,7 +228,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
|
||||
// Therefore they are not some form of constructor `C`,
|
||||
// with which a pattern `C(p_0)` may be formed,
|
||||
// which we would want to join with other `C(p_j)`s.
|
||||
Ident(.., None) | Lit(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_)
|
||||
Ident(.., None) | Expr(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_)
|
||||
// Skip immutable refs, as grouping them saves few characters,
|
||||
// and almost always requires adding parens (increasing noisiness).
|
||||
// In the case of only two patterns, replacement adds net characters.
|
||||
|
@ -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 {
|
||||
@ -717,17 +738,17 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
||||
kind!("Guard({pat}, {cond})");
|
||||
self.pat(pat);
|
||||
self.expr(cond);
|
||||
}
|
||||
PatKind::Lit(lit_expr) => {
|
||||
},
|
||||
PatKind::Expr(lit_expr) => {
|
||||
bind!(self, lit_expr);
|
||||
kind!("Lit({lit_expr})");
|
||||
self.expr(lit_expr);
|
||||
kind!("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);
|
||||
|
@ -36,7 +36,7 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
|
||||
(Paren(l), _) => eq_pat(l, r),
|
||||
(_, Paren(r)) => eq_pat(l, r),
|
||||
(Wild, Wild) | (Rest, Rest) => true,
|
||||
(Lit(l), Lit(r)) => eq_expr(l, r),
|
||||
(Expr(l), Expr(r)) => eq_expr(l, r),
|
||||
(Ident(b1, i1, s1), Ident(b2, i2, s2)) => {
|
||||
b1 == b2 && eq_id(*i1, *i2) && both(s1.as_deref(), s2.as_deref(), eq_pat)
|
||||
},
|
||||
|
@ -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::Expr(l), &PatKind::Expr(r)) => self.eq_pat_expr(l, r),
|
||||
(&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
|
||||
(&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
|
||||
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::Expr(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);
|
||||
},
|
||||
|
@ -1777,7 +1777,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
|
||||
},
|
||||
}
|
||||
},
|
||||
PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) | PatKind::Guard(..) => true,
|
||||
PatKind::Expr(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) | PatKind::Guard(..) => true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,8 +30,8 @@ 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 PatKind::Expr(lit_expr) = let_expr.pat.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"])
|
||||
|
@ -76,8 +76,8 @@ if let Some(higher::While { condition: condition, body: body }) = higher::While:
|
||||
// report your lint here
|
||||
}
|
||||
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 PatKind::Expr(lit_expr) = let_pat.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"])
|
||||
|
@ -4,14 +4,14 @@ if let StmtKind::Let(local) = stmt.kind
|
||||
&& let ExprKind::Lit(ref lit) = scrutinee.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 PatKind::Expr(lit_expr) = arms[0].pat.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 PatKind::Expr(lit_expr1) = arms[1].pat.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
|
||||
|
@ -23,8 +23,8 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind
|
||||
&& match_qpath(qpath, &["Test"])
|
||||
&& 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 PatKind::Expr(lit_expr) = fields[0].pat.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
|
||||
@ -36,8 +36,8 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind
|
||||
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 PatKind::Expr(lit_expr) = fields[0].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
|
||||
|
@ -42,7 +42,7 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
|
||||
| ast::PatKind::Never
|
||||
| ast::PatKind::Wild
|
||||
| ast::PatKind::Err(_)
|
||||
| ast::PatKind::Lit(_) => true,
|
||||
| ast::PatKind::Expr(_) => true,
|
||||
ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
|
||||
ast::PatKind::Struct(..)
|
||||
| ast::PatKind::MacCall(..)
|
||||
@ -293,7 +293,7 @@ impl Rewrite for Pat {
|
||||
let path_str = rewrite_path(context, PathContext::Expr, q_self, path, shape)?;
|
||||
rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape)
|
||||
}
|
||||
PatKind::Lit(ref expr) => expr.rewrite_result(context, shape),
|
||||
PatKind::Expr(ref expr) => expr.rewrite_result(context, shape),
|
||||
PatKind::Slice(ref slice_pat)
|
||||
if context.config.style_edition() <= StyleEdition::Edition2021 =>
|
||||
{
|
||||
@ -530,7 +530,7 @@ pub(crate) fn can_be_overflowed_pat(
|
||||
ast::PatKind::Ref(ref p, _) | ast::PatKind::Box(ref p) => {
|
||||
can_be_overflowed_pat(context, &TuplePatField::Pat(p), len)
|
||||
}
|
||||
ast::PatKind::Lit(ref expr) => can_be_overflowed_expr(context, expr, len),
|
||||
ast::PatKind::Expr(ref expr) => can_be_overflowed_expr(context, expr, len),
|
||||
_ => false,
|
||||
},
|
||||
TuplePatField::Dotdot(..) => false,
|
||||
|
@ -569,7 +569,7 @@ fn test_pat() {
|
||||
c1!(pat, [ &pat ], "&pat");
|
||||
c1!(pat, [ &mut pat ], "&mut pat");
|
||||
|
||||
// PatKind::Lit
|
||||
// PatKind::Expr
|
||||
c1!(pat, [ 1_000_i8 ], "1_000_i8");
|
||||
|
||||
// PatKind::Range
|
||||
|
@ -6,7 +6,7 @@ macro_rules! enum_number {
|
||||
|
||||
fn foo(value: i32) -> Option<$name> {
|
||||
match value {
|
||||
$( $value => Some($name::$variant), )* // PatKind::Lit
|
||||
$( $value => Some($name::$variant), )* // PatKind::Expr
|
||||
$( $value ..= 42 => Some($name::$variant), )* // PatKind::Range
|
||||
_ => None
|
||||
}
|
||||
|
@ -651,8 +651,8 @@ mod patterns {
|
||||
let &mut pat;
|
||||
}
|
||||
|
||||
/// PatKind::Lit
|
||||
fn pat_lit() {
|
||||
/// PatKind::Expr
|
||||
fn pat_expr() {
|
||||
let 1_000_i8;
|
||||
let -"";
|
||||
}
|
||||
|
@ -567,8 +567,8 @@ mod patterns {
|
||||
fn pat_deref() { let deref!(pat); }
|
||||
/// PatKind::Ref
|
||||
fn pat_ref() { let &pat; let &mut pat; }
|
||||
/// PatKind::Lit
|
||||
fn pat_lit() { let 1_000_i8; let -""; }
|
||||
/// PatKind::Expr
|
||||
fn pat_expr() { let 1_000_i8; let -""; }
|
||||
/// PatKind::Range
|
||||
fn pat_range() { let ..1; let 0..; let 0..1; let 0..=1; let -2..=-1; }
|
||||
/// PatKind::Slice
|
||||
|
@ -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