Auto merge of #146069 - camsteffen:range-desugar-span, r=SparrowLii
Mark desugared range expression spans with DesugaringKind::RangeExpr This is a prerequisite to removing `QPath::LangItem` (rust-lang/rust#115178) because otherwise there would be no way to detect a range expression in the HIR. There are some non-obvious Clippy changes so a Clippy team review would be good.
This commit is contained in:
@@ -63,13 +63,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
|
|
||||||
pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
|
pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
|
||||||
ensure_sufficient_stack(|| {
|
ensure_sufficient_stack(|| {
|
||||||
|
let mut span = self.lower_span(e.span);
|
||||||
match &e.kind {
|
match &e.kind {
|
||||||
// Parenthesis expression does not have a HirId and is handled specially.
|
// Parenthesis expression does not have a HirId and is handled specially.
|
||||||
ExprKind::Paren(ex) => {
|
ExprKind::Paren(ex) => {
|
||||||
let mut ex = self.lower_expr_mut(ex);
|
let mut ex = self.lower_expr_mut(ex);
|
||||||
// Include parens in span, but only if it is a super-span.
|
// Include parens in span, but only if it is a super-span.
|
||||||
if e.span.contains(ex.span) {
|
if e.span.contains(ex.span) {
|
||||||
ex.span = self.lower_span(e.span);
|
ex.span = self.lower_span(e.span.with_ctxt(ex.span.ctxt()));
|
||||||
}
|
}
|
||||||
// Merge attributes into the inner expression.
|
// Merge attributes into the inner expression.
|
||||||
if !e.attrs.is_empty() {
|
if !e.attrs.is_empty() {
|
||||||
@@ -288,7 +289,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
self.lower_span(*brackets_span),
|
self.lower_span(*brackets_span),
|
||||||
),
|
),
|
||||||
ExprKind::Range(e1, e2, lims) => {
|
ExprKind::Range(e1, e2, lims) => {
|
||||||
self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims)
|
span = self.mark_span_with_reason(DesugaringKind::RangeExpr, span, None);
|
||||||
|
self.lower_expr_range(span, e1.as_deref(), e2.as_deref(), *lims)
|
||||||
}
|
}
|
||||||
ExprKind::Underscore => {
|
ExprKind::Underscore => {
|
||||||
let guar = self.dcx().emit_err(UnderscoreExprLhsAssign { span: e.span });
|
let guar = self.dcx().emit_err(UnderscoreExprLhsAssign { span: e.span });
|
||||||
@@ -380,7 +382,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
|
ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
|
||||||
};
|
};
|
||||||
|
|
||||||
hir::Expr { hir_id: expr_hir_id, kind, span: self.lower_span(e.span) }
|
hir::Expr { hir_id: expr_hir_id, kind, span }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1482,7 +1484,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
|
fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
|
||||||
let e1 = self.lower_expr_mut(e1);
|
let e1 = self.lower_expr_mut(e1);
|
||||||
let e2 = self.lower_expr_mut(e2);
|
let e2 = self.lower_expr_mut(e2);
|
||||||
let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span));
|
let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, span);
|
||||||
let fn_expr = self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path)));
|
let fn_expr = self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path)));
|
||||||
hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
|
hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
|
||||||
}
|
}
|
||||||
@@ -1559,14 +1561,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
.map(|(s, e)| {
|
.map(|(s, e)| {
|
||||||
|
let span = self.lower_span(e.span);
|
||||||
|
let span = self.mark_span_with_reason(DesugaringKind::RangeExpr, span, None);
|
||||||
let expr = self.lower_expr(e);
|
let expr = self.lower_expr(e);
|
||||||
let ident = Ident::new(s, self.lower_span(e.span));
|
let ident = Ident::new(s, span);
|
||||||
self.expr_field(ident, expr, e.span)
|
self.expr_field(ident, expr, span)
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
hir::ExprKind::Struct(
|
hir::ExprKind::Struct(
|
||||||
self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span))),
|
self.arena.alloc(hir::QPath::LangItem(lang_item, span)),
|
||||||
fields,
|
fields,
|
||||||
hir::StructTailExpr::None,
|
hir::StructTailExpr::None,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2460,6 +2460,12 @@ impl Expr<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If this is a desugared range expression,
|
||||||
|
/// returns the span of the range without desugaring context.
|
||||||
|
pub fn range_span(&self) -> Option<Span> {
|
||||||
|
is_range_literal(self).then(|| self.span.parent_callsite().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if expression is an integer literal that can be used
|
/// Check if expression is an integer literal that can be used
|
||||||
/// where `usize` is expected.
|
/// where `usize` is expected.
|
||||||
pub fn is_size_lit(&self) -> bool {
|
pub fn is_size_lit(&self) -> bool {
|
||||||
|
|||||||
@@ -2509,11 +2509,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.tcx
|
.tcx
|
||||||
.sess
|
.sess
|
||||||
.source_map()
|
.source_map()
|
||||||
.span_extend_while_whitespace(range_start.span)
|
.span_extend_while_whitespace(range_start.expr.span)
|
||||||
.shrink_to_hi()
|
.shrink_to_hi()
|
||||||
.to(range_end.span);
|
.to(range_end.expr.span);
|
||||||
|
|
||||||
err.subdiagnostic(TypeMismatchFruTypo { expr_span: range_start.span, fru_span, expr });
|
err.subdiagnostic(TypeMismatchFruTypo {
|
||||||
|
expr_span: range_start.expr.span,
|
||||||
|
fru_span,
|
||||||
|
expr,
|
||||||
|
});
|
||||||
|
|
||||||
// Suppress any range expr type mismatches
|
// Suppress any range expr type mismatches
|
||||||
self.dcx().try_steal_replace_and_emit_err(
|
self.dcx().try_steal_replace_and_emit_err(
|
||||||
|
|||||||
@@ -1666,7 +1666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [start, end], _) => {
|
ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [start, end], _) => {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
start.span.shrink_to_hi().with_hi(end.span.lo()),
|
start.expr.span.shrink_to_hi().with_hi(end.expr.span.lo()),
|
||||||
"remove the unnecessary `.` operator for a floating point literal",
|
"remove the unnecessary `.` operator for a floating point literal",
|
||||||
'.',
|
'.',
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
@@ -1674,8 +1674,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, ..), [start], _) => {
|
ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, ..), [start], _) => {
|
||||||
|
let range_span = expr.span.parent_callsite().unwrap();
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
expr.span.with_lo(start.span.hi()),
|
range_span.with_lo(start.expr.span.hi()),
|
||||||
"remove the unnecessary `.` operator for a floating point literal",
|
"remove the unnecessary `.` operator for a floating point literal",
|
||||||
'.',
|
'.',
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
@@ -1683,8 +1684,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, ..), [end], _) => {
|
ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, ..), [end], _) => {
|
||||||
|
let range_span = expr.span.parent_callsite().unwrap();
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
expr.span.until(end.span),
|
range_span.until(end.expr.span),
|
||||||
"remove the unnecessary `.` operator and add an integer part for a floating point literal",
|
"remove the unnecessary `.` operator and add an integer part for a floating point literal",
|
||||||
"0.",
|
"0.",
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
@@ -2693,7 +2695,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
bool, /* suggest `&` or `&mut` type annotation */
|
bool, /* suggest `&` or `&mut` type annotation */
|
||||||
)> {
|
)> {
|
||||||
let sess = self.sess();
|
let sess = self.sess();
|
||||||
let sp = expr.span;
|
let sp = expr.range_span().unwrap_or(expr.span);
|
||||||
let sm = sess.source_map();
|
let sm = sess.source_map();
|
||||||
|
|
||||||
// If the span is from an external macro, there's no suggestion we can make.
|
// If the span is from an external macro, there's no suggestion we can make.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use hir::{ExprKind, Node, is_range_literal};
|
use hir::{ExprKind, Node};
|
||||||
use rustc_abi::{Integer, Size};
|
use rustc_abi::{Integer, Size};
|
||||||
use rustc_hir::{HirId, attrs};
|
use rustc_hir::{HirId, attrs};
|
||||||
use rustc_middle::ty::Ty;
|
use rustc_middle::ty::Ty;
|
||||||
@@ -44,7 +44,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
|
|||||||
let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else {
|
let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
if !is_range_literal(struct_expr) {
|
let Some(range_span) = struct_expr.range_span() else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else {
|
let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else {
|
||||||
@@ -71,7 +71,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
UseInclusiveRange::WithoutParen {
|
UseInclusiveRange::WithoutParen {
|
||||||
sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()),
|
sugg: range_span.shrink_to_lo().to(lit_span.shrink_to_hi()),
|
||||||
start,
|
start,
|
||||||
literal: lit_val - 1,
|
literal: lit_val - 1,
|
||||||
suffix,
|
suffix,
|
||||||
@@ -87,7 +87,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
|
|||||||
|
|
||||||
cx.emit_span_lint(
|
cx.emit_span_lint(
|
||||||
OVERFLOWING_LITERALS,
|
OVERFLOWING_LITERALS,
|
||||||
struct_expr.span,
|
range_span,
|
||||||
RangeEndpointOutOfRange { ty, sub: sub_sugg },
|
RangeEndpointOutOfRange { ty, sub: sub_sugg },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1247,6 +1247,7 @@ pub enum DesugaringKind {
|
|||||||
/// rewriting it.
|
/// rewriting it.
|
||||||
source: bool,
|
source: bool,
|
||||||
},
|
},
|
||||||
|
RangeExpr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DesugaringKind {
|
impl DesugaringKind {
|
||||||
@@ -1268,6 +1269,7 @@ impl DesugaringKind {
|
|||||||
DesugaringKind::FormatLiteral { source: false } => {
|
DesugaringKind::FormatLiteral { source: false } => {
|
||||||
"expression that expanded into a format string literal"
|
"expression that expanded into a format string literal"
|
||||||
}
|
}
|
||||||
|
DesugaringKind::RangeExpr => "range expression",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1287,6 +1289,7 @@ impl DesugaringKind {
|
|||||||
DesugaringKind::Contract => value == "Contract",
|
DesugaringKind::Contract => value == "Contract",
|
||||||
DesugaringKind::PatTyRange => value == "PatTyRange",
|
DesugaringKind::PatTyRange => value == "PatTyRange",
|
||||||
DesugaringKind::FormatLiteral { .. } => value == "FormatLiteral",
|
DesugaringKind::FormatLiteral { .. } => value == "FormatLiteral",
|
||||||
|
DesugaringKind::RangeExpr => value == "RangeExpr",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use rustc_hir::intravisit::{Visitor, VisitorExt};
|
|||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
self as hir, AmbigArg, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node,
|
self as hir, AmbigArg, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node,
|
||||||
expr_needs_parens, is_range_literal,
|
expr_needs_parens,
|
||||||
};
|
};
|
||||||
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk};
|
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk};
|
||||||
use rustc_middle::middle::privacy::Level;
|
use rustc_middle::middle::privacy::Level;
|
||||||
@@ -668,12 +668,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
let derefs = "*".repeat(steps);
|
let derefs = "*".repeat(steps);
|
||||||
let needs_parens = steps > 0
|
let needs_parens = steps > 0 && expr_needs_parens(expr);
|
||||||
&& match expr.kind {
|
|
||||||
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
|
|
||||||
_ if is_range_literal(expr) => true,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
let mut suggestion = if needs_parens {
|
let mut suggestion = if needs_parens {
|
||||||
vec![
|
vec![
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ pub(super) fn check<'tcx>(
|
|||||||
start: Some(start),
|
start: Some(start),
|
||||||
end: Some(end),
|
end: Some(end),
|
||||||
limits,
|
limits,
|
||||||
|
span: _,
|
||||||
}) = higher::Range::hir(arg)
|
}) = higher::Range::hir(arg)
|
||||||
// the var must be a single name
|
// the var must be a single name
|
||||||
&& let PatKind::Binding(_, canonical_id, _, _) = pat.kind
|
&& let PatKind::Binding(_, canonical_id, _, _) = pat.kind
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ pub(super) fn check<'tcx>(
|
|||||||
start: Some(start),
|
start: Some(start),
|
||||||
end: Some(end),
|
end: Some(end),
|
||||||
limits: RangeLimits::HalfOpen,
|
limits: RangeLimits::HalfOpen,
|
||||||
|
span: _,
|
||||||
}) = higher::Range::hir(arg)
|
}) = higher::Range::hir(arg)
|
||||||
&& let ExprKind::Lit(Spanned {
|
&& let ExprKind::Lit(Spanned {
|
||||||
node: LitKind::Int(Pu128(0), _),
|
node: LitKind::Int(Pu128(0), _),
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ pub(super) fn check<'tcx>(
|
|||||||
start: Some(start),
|
start: Some(start),
|
||||||
ref end,
|
ref end,
|
||||||
limits,
|
limits,
|
||||||
|
span,
|
||||||
}) = higher::Range::hir(arg)
|
}) = higher::Range::hir(arg)
|
||||||
// the var must be a single name
|
// the var must be a single name
|
||||||
&& let PatKind::Binding(_, canonical_id, ident, _) = pat.kind
|
&& let PatKind::Binding(_, canonical_id, ident, _) = pat.kind
|
||||||
@@ -149,7 +150,7 @@ pub(super) fn check<'tcx>(
|
|||||||
span_lint_and_then(
|
span_lint_and_then(
|
||||||
cx,
|
cx,
|
||||||
NEEDLESS_RANGE_LOOP,
|
NEEDLESS_RANGE_LOOP,
|
||||||
arg.span,
|
span,
|
||||||
format!("the loop variable `{}` is used to index `{indexed}`", ident.name),
|
format!("the loop variable `{}` is used to index `{indexed}`", ident.name),
|
||||||
|diag| {
|
|diag| {
|
||||||
diag.multipart_suggestion(
|
diag.multipart_suggestion(
|
||||||
@@ -157,7 +158,7 @@ pub(super) fn check<'tcx>(
|
|||||||
vec![
|
vec![
|
||||||
(pat.span, format!("({}, <item>)", ident.name)),
|
(pat.span, format!("({}, <item>)", ident.name)),
|
||||||
(
|
(
|
||||||
arg.span,
|
span,
|
||||||
format!("{indexed}.{method}().enumerate(){method_1}{method_2}"),
|
format!("{indexed}.{method}().enumerate(){method_1}{method_2}"),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -175,12 +176,12 @@ pub(super) fn check<'tcx>(
|
|||||||
span_lint_and_then(
|
span_lint_and_then(
|
||||||
cx,
|
cx,
|
||||||
NEEDLESS_RANGE_LOOP,
|
NEEDLESS_RANGE_LOOP,
|
||||||
arg.span,
|
span,
|
||||||
format!("the loop variable `{}` is only used to index `{indexed}`", ident.name),
|
format!("the loop variable `{}` is only used to index `{indexed}`", ident.name),
|
||||||
|diag| {
|
|diag| {
|
||||||
diag.multipart_suggestion(
|
diag.multipart_suggestion(
|
||||||
"consider using an iterator",
|
"consider using an iterator",
|
||||||
vec![(pat.span, "<item>".to_string()), (arg.span, repl)],
|
vec![(pat.span, "<item>".to_string()), (span, repl)],
|
||||||
Applicability::HasPlaceholders,
|
Applicability::HasPlaceholders,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
|
|||||||
start: Some(start),
|
start: Some(start),
|
||||||
end: Some(end),
|
end: Some(end),
|
||||||
limits: RangeLimits::Closed,
|
limits: RangeLimits::Closed,
|
||||||
|
span: _,
|
||||||
}) = higher::Range::hir(receiver)
|
}) = higher::Range::hir(receiver)
|
||||||
&& !matches!(cx.typeck_results().expr_ty(arg).peel_refs().kind(), ty::Param(_))
|
&& !matches!(cx.typeck_results().expr_ty(arg).peel_refs().kind(), ty::Param(_))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
|
|||||||
start: Some(start_expr),
|
start: Some(start_expr),
|
||||||
end: None,
|
end: None,
|
||||||
limits: ast::RangeLimits::HalfOpen,
|
limits: ast::RangeLimits::HalfOpen,
|
||||||
|
span: _,
|
||||||
}) = higher::Range::hir(index_expr)
|
}) = higher::Range::hir(index_expr)
|
||||||
&& let hir::ExprKind::Lit(start_lit) = &start_expr.kind
|
&& let hir::ExprKind::Lit(start_lit) = &start_expr.kind
|
||||||
&& let ast::LitKind::Int(start_idx, _) = start_lit.node
|
&& let ast::LitKind::Int(start_idx, _) = start_lit.node
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ pub(super) fn check(
|
|||||||
receiver: &Expr<'_>,
|
receiver: &Expr<'_>,
|
||||||
arg: &Expr<'_>,
|
arg: &Expr<'_>,
|
||||||
msrv: Msrv,
|
msrv: Msrv,
|
||||||
method_call_span: Span,
|
method_name_span: Span,
|
||||||
) {
|
) {
|
||||||
let mut applicability = Applicability::MaybeIncorrect;
|
let mut applicability = Applicability::MaybeIncorrect;
|
||||||
if let Some(range) = higher::Range::hir(receiver)
|
if let Some(range) = higher::Range::hir(receiver)
|
||||||
@@ -105,7 +105,7 @@ pub(super) fn check(
|
|||||||
// collate all our parts here and then remove those that are empty.
|
// collate all our parts here and then remove those that are empty.
|
||||||
let mut parts = vec![
|
let mut parts = vec![
|
||||||
(
|
(
|
||||||
receiver.span.to(method_call_span),
|
ex.span.with_hi(method_name_span.hi()),
|
||||||
format!("{exec_context}::iter::{method_to_use_name}"),
|
format!("{exec_context}::iter::{method_to_use_name}"),
|
||||||
),
|
),
|
||||||
new_span,
|
new_span,
|
||||||
|
|||||||
@@ -4854,8 +4854,8 @@ impl_lint_pass!(Methods => [
|
|||||||
/// come from expansion.
|
/// come from expansion.
|
||||||
pub fn method_call<'tcx>(recv: &'tcx Expr<'tcx>) -> Option<(Symbol, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> {
|
pub fn method_call<'tcx>(recv: &'tcx Expr<'tcx>) -> Option<(Symbol, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> {
|
||||||
if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind
|
if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind
|
||||||
&& !args.iter().any(|e| e.span.from_expansion())
|
&& !args.iter().any(|e| e.range_span().unwrap_or(e.span).from_expansion())
|
||||||
&& !receiver.span.from_expansion()
|
&& !receiver.range_span().unwrap_or(receiver.span).from_expansion()
|
||||||
{
|
{
|
||||||
Some((path.ident.name, receiver, args, path.ident.span, call_span))
|
Some((path.ident.name, receiver, args, path.ident.span, call_span))
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ impl NoEffect {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if expr.span.from_expansion() {
|
if expr.range_span().unwrap_or(expr.span).from_expansion() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let expr = peel_blocks(expr);
|
let expr = peel_blocks(expr);
|
||||||
@@ -273,7 +273,7 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
|
|||||||
if let StmtKind::Semi(expr) = stmt.kind
|
if let StmtKind::Semi(expr) = stmt.kind
|
||||||
&& !stmt.span.in_external_macro(cx.sess().source_map())
|
&& !stmt.span.in_external_macro(cx.sess().source_map())
|
||||||
&& let ctxt = stmt.span.ctxt()
|
&& let ctxt = stmt.span.ctxt()
|
||||||
&& expr.span.ctxt() == ctxt
|
&& expr.range_span().unwrap_or(expr.span).ctxt() == ctxt
|
||||||
&& let Some(reduced) = reduce_expression(cx, expr)
|
&& let Some(reduced) = reduce_expression(cx, expr)
|
||||||
&& reduced.iter().all(|e| e.span.ctxt() == ctxt)
|
&& reduced.iter().all(|e| e.span.ctxt() == ctxt)
|
||||||
{
|
{
|
||||||
@@ -330,7 +330,7 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec<&'a Expr<'a>>> {
|
fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec<&'a Expr<'a>>> {
|
||||||
if expr.span.from_expansion() {
|
if expr.range_span().unwrap_or(expr.span).from_expansion() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
|
|||||||
@@ -501,17 +501,18 @@ fn check_range_switch<'tcx>(
|
|||||||
msg: &'static str,
|
msg: &'static str,
|
||||||
operator: &str,
|
operator: &str,
|
||||||
) {
|
) {
|
||||||
if expr.span.can_be_used_for_suggestions()
|
if let Some(range) = higher::Range::hir(expr)
|
||||||
&& let Some(higher::Range {
|
&& let higher::Range {
|
||||||
start,
|
start,
|
||||||
end: Some(end),
|
end: Some(end),
|
||||||
limits,
|
limits,
|
||||||
}) = higher::Range::hir(expr)
|
span,
|
||||||
|
} = range
|
||||||
|
&& span.can_be_used_for_suggestions()
|
||||||
&& limits == kind
|
&& limits == kind
|
||||||
&& let Some(y) = predicate(cx, end)
|
&& let Some(y) = predicate(cx, end)
|
||||||
&& can_switch_ranges(cx, expr, kind, cx.typeck_results().expr_ty(y))
|
&& can_switch_ranges(cx, expr, kind, cx.typeck_results().expr_ty(y))
|
||||||
{
|
{
|
||||||
let span = expr.span;
|
|
||||||
span_lint_and_then(cx, lint, span, msg, |diag| {
|
span_lint_and_then(cx, lint, span, msg, |diag| {
|
||||||
let mut app = Applicability::MachineApplicable;
|
let mut app = Applicability::MachineApplicable;
|
||||||
let start = start.map_or(String::new(), |x| {
|
let start = start.map_or(String::new(), |x| {
|
||||||
@@ -567,6 +568,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||||||
start: Some(start),
|
start: Some(start),
|
||||||
end: Some(end),
|
end: Some(end),
|
||||||
limits,
|
limits,
|
||||||
|
span,
|
||||||
}) = higher::Range::hir(expr)
|
}) = higher::Range::hir(expr)
|
||||||
&& let ty = cx.typeck_results().expr_ty(start)
|
&& let ty = cx.typeck_results().expr_ty(start)
|
||||||
&& let ty::Int(_) | ty::Uint(_) = ty.kind()
|
&& let ty::Int(_) | ty::Uint(_) = ty.kind()
|
||||||
@@ -582,7 +584,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||||||
span_lint(
|
span_lint(
|
||||||
cx,
|
cx,
|
||||||
REVERSED_EMPTY_RANGES,
|
REVERSED_EMPTY_RANGES,
|
||||||
expr.span,
|
span,
|
||||||
"this range is reversed and using it to index a slice will panic at run-time",
|
"this range is reversed and using it to index a slice will panic at run-time",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -591,7 +593,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||||||
span_lint_and_then(
|
span_lint_and_then(
|
||||||
cx,
|
cx,
|
||||||
REVERSED_EMPTY_RANGES,
|
REVERSED_EMPTY_RANGES,
|
||||||
expr.span,
|
span,
|
||||||
"this range is empty so it will yield no values",
|
"this range is empty so it will yield no values",
|
||||||
|diag| {
|
|diag| {
|
||||||
if ordering != Ordering::Equal {
|
if ordering != Ordering::Equal {
|
||||||
@@ -603,7 +605,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
diag.span_suggestion(
|
diag.span_suggestion(
|
||||||
expr.span,
|
span,
|
||||||
"consider using the following if you are attempting to iterate over this \
|
"consider using the following if you are attempting to iterate over this \
|
||||||
range in reverse",
|
range in reverse",
|
||||||
format!("({end_snippet}{dots}{start_snippet}).rev()"),
|
format!("({end_snippet}{dots}{start_snippet}).rev()"),
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use clippy_utils::{get_parent_expr, is_mutable};
|
|||||||
use rustc_hir::{Expr, ExprField, ExprKind, Path, QPath, StructTailExpr, UnOp};
|
use rustc_hir::{Expr, ExprField, ExprKind, Path, QPath, StructTailExpr, UnOp};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
|
use rustc_span::{DesugaringKind, Ident};
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
@@ -52,7 +53,8 @@ impl LateLintPass<'_> for UnnecessaryStruct {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if expr.span.from_expansion() {
|
let expr_span = expr.range_span().unwrap_or(expr.span);
|
||||||
|
if expr_span.from_expansion() {
|
||||||
// Prevent lint from hitting inside macro code
|
// Prevent lint from hitting inside macro code
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -80,7 +82,7 @@ impl LateLintPass<'_> for UnnecessaryStruct {
|
|||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
UNNECESSARY_STRUCT_INITIALIZATION,
|
UNNECESSARY_STRUCT_INITIALIZATION,
|
||||||
expr.span,
|
expr_span,
|
||||||
"unnecessary struct building",
|
"unnecessary struct building",
|
||||||
"replace with",
|
"replace with",
|
||||||
snippet(cx, sugg, "..").into_owned(),
|
snippet(cx, sugg, "..").into_owned(),
|
||||||
@@ -130,7 +132,7 @@ fn same_path_in_all_fields<'tcx>(
|
|||||||
// expression type matches
|
// expression type matches
|
||||||
&& ty == cx.typeck_results().expr_ty(src_expr)
|
&& ty == cx.typeck_results().expr_ty(src_expr)
|
||||||
// field name matches
|
// field name matches
|
||||||
&& f.ident == ident
|
&& ident_without_range_desugaring(f.ident) == ident
|
||||||
// assigned from a path expression
|
// assigned from a path expression
|
||||||
&& let ExprKind::Path(QPath::Resolved(None, src_path)) = src_expr.kind
|
&& let ExprKind::Path(QPath::Resolved(None, src_path)) = src_expr.kind
|
||||||
{
|
{
|
||||||
@@ -197,3 +199,14 @@ fn path_matches_base(path: &Path<'_>, base: &Expr<'_>) -> bool {
|
|||||||
};
|
};
|
||||||
path.res == base_path.res
|
path.res == base_path.res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ident_without_range_desugaring(ident: Ident) -> Ident {
|
||||||
|
if ident.span.desugaring_kind() == Some(DesugaringKind::RangeExpr) {
|
||||||
|
Ident {
|
||||||
|
span: ident.span.parent_callsite().unwrap(),
|
||||||
|
..ident
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ident
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -209,12 +209,14 @@ pub struct Range<'a> {
|
|||||||
pub end: Option<&'a Expr<'a>>,
|
pub end: Option<&'a Expr<'a>>,
|
||||||
/// Whether the interval is open or closed.
|
/// Whether the interval is open or closed.
|
||||||
pub limits: ast::RangeLimits,
|
pub limits: ast::RangeLimits,
|
||||||
|
pub span: Span
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Range<'a> {
|
impl<'a> Range<'a> {
|
||||||
/// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
|
/// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
|
||||||
#[expect(clippy::similar_names)]
|
#[expect(clippy::similar_names)]
|
||||||
pub fn hir(expr: &'a Expr<'_>) -> Option<Range<'a>> {
|
pub fn hir(expr: &'a Expr<'_>) -> Option<Range<'a>> {
|
||||||
|
let span = expr.range_span()?;
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::Call(path, [arg1, arg2])
|
ExprKind::Call(path, [arg1, arg2])
|
||||||
if matches!(
|
if matches!(
|
||||||
@@ -226,6 +228,7 @@ impl<'a> Range<'a> {
|
|||||||
start: Some(arg1),
|
start: Some(arg1),
|
||||||
end: Some(arg2),
|
end: Some(arg2),
|
||||||
limits: ast::RangeLimits::Closed,
|
limits: ast::RangeLimits::Closed,
|
||||||
|
span,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ExprKind::Struct(path, fields, StructTailExpr::None) => match (path, fields) {
|
ExprKind::Struct(path, fields, StructTailExpr::None) => match (path, fields) {
|
||||||
@@ -233,12 +236,14 @@ impl<'a> Range<'a> {
|
|||||||
start: None,
|
start: None,
|
||||||
end: None,
|
end: None,
|
||||||
limits: ast::RangeLimits::HalfOpen,
|
limits: ast::RangeLimits::HalfOpen,
|
||||||
|
span,
|
||||||
}),
|
}),
|
||||||
(QPath::LangItem(hir::LangItem::RangeFrom, ..), [field]) if field.ident.name == sym::start => {
|
(QPath::LangItem(hir::LangItem::RangeFrom, ..), [field]) if field.ident.name == sym::start => {
|
||||||
Some(Range {
|
Some(Range {
|
||||||
start: Some(field.expr),
|
start: Some(field.expr),
|
||||||
end: None,
|
end: None,
|
||||||
limits: ast::RangeLimits::HalfOpen,
|
limits: ast::RangeLimits::HalfOpen,
|
||||||
|
span,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
(QPath::LangItem(hir::LangItem::Range, ..), [field1, field2]) => {
|
(QPath::LangItem(hir::LangItem::Range, ..), [field1, field2]) => {
|
||||||
@@ -251,6 +256,7 @@ impl<'a> Range<'a> {
|
|||||||
start: Some(start),
|
start: Some(start),
|
||||||
end: Some(end),
|
end: Some(end),
|
||||||
limits: ast::RangeLimits::HalfOpen,
|
limits: ast::RangeLimits::HalfOpen,
|
||||||
|
span,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
(QPath::LangItem(hir::LangItem::RangeToInclusive, ..), [field]) if field.ident.name == sym::end => {
|
(QPath::LangItem(hir::LangItem::RangeToInclusive, ..), [field]) if field.ident.name == sym::end => {
|
||||||
@@ -258,12 +264,14 @@ impl<'a> Range<'a> {
|
|||||||
start: None,
|
start: None,
|
||||||
end: Some(field.expr),
|
end: Some(field.expr),
|
||||||
limits: ast::RangeLimits::Closed,
|
limits: ast::RangeLimits::Closed,
|
||||||
|
span,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
(QPath::LangItem(hir::LangItem::RangeTo, ..), [field]) if field.ident.name == sym::end => Some(Range {
|
(QPath::LangItem(hir::LangItem::RangeTo, ..), [field]) if field.ident.name == sym::end => Some(Range {
|
||||||
start: None,
|
start: None,
|
||||||
end: Some(field.expr),
|
end: Some(field.expr),
|
||||||
limits: ast::RangeLimits::HalfOpen,
|
limits: ast::RangeLimits::HalfOpen,
|
||||||
|
span,
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1282,7 +1282,7 @@ pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
|
|||||||
/// If the given `Expr` is not some kind of range, the function returns `false`.
|
/// If the given `Expr` is not some kind of range, the function returns `false`.
|
||||||
pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool {
|
pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool {
|
||||||
let ty = cx.typeck_results().expr_ty(expr);
|
let ty = cx.typeck_results().expr_ty(expr);
|
||||||
if let Some(Range { start, end, limits }) = Range::hir(expr) {
|
if let Some(Range { start, end, limits, .. }) = Range::hir(expr) {
|
||||||
let start_is_none_or_min = start.is_none_or(|start| {
|
let start_is_none_or_min = start.is_none_or(|start| {
|
||||||
if let rustc_ty::Adt(_, subst) = ty.kind()
|
if let rustc_ty::Adt(_, subst) = ty.kind()
|
||||||
&& let bnd_ty = subst.type_at(0)
|
&& let bnd_ty = subst.type_at(0)
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ use rustc_middle::ty::TyCtxt;
|
|||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::source_map::{SourceMap, original_sp};
|
use rustc_span::source_map::{SourceMap, original_sp};
|
||||||
use rustc_span::{
|
use rustc_span::{
|
||||||
BytePos, DUMMY_SP, FileNameDisplayPreference, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, Span, SpanData,
|
BytePos, DesugaringKind, DUMMY_SP, FileNameDisplayPreference, Pos, RelativeBytePos, SourceFile, SourceFileAndLine,
|
||||||
SyntaxContext, hygiene,
|
Span, SpanData, SyntaxContext, hygiene,
|
||||||
};
|
};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@@ -670,6 +670,14 @@ fn snippet_with_context_sess<'a>(
|
|||||||
default: &'a str,
|
default: &'a str,
|
||||||
applicability: &mut Applicability,
|
applicability: &mut Applicability,
|
||||||
) -> (Cow<'a, str>, bool) {
|
) -> (Cow<'a, str>, bool) {
|
||||||
|
// If it is just range desugaring, use the desugaring span since it may include parenthesis.
|
||||||
|
if span.desugaring_kind() == Some(DesugaringKind::RangeExpr) && span.parent_callsite().unwrap().ctxt() == outer {
|
||||||
|
return (
|
||||||
|
snippet_with_applicability_sess(sess, span, default, applicability),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
let (span, is_macro_call) = walk_span_to_context(span, outer).map_or_else(
|
let (span, is_macro_call) = walk_span_to_context(span, outer).map_or_else(
|
||||||
|| {
|
|| {
|
||||||
// The span is from a macro argument, and the outer context is the macro using the argument
|
// The span is from a macro argument, and the outer context is the macro using the argument
|
||||||
|
|||||||
@@ -32,22 +32,22 @@ LL | for _ in 1..ONE + ONE {}
|
|||||||
| ^^^^^^^^^^^^ help: use: `1..=ONE`
|
| ^^^^^^^^^^^^ help: use: `1..=ONE`
|
||||||
|
|
||||||
error: an inclusive range would be more readable
|
error: an inclusive range would be more readable
|
||||||
--> tests/ui/range_plus_minus_one.rs:70:5
|
--> tests/ui/range_plus_minus_one.rs:70:6
|
||||||
|
|
|
|
||||||
LL | (1..10 + 1).for_each(|_| {});
|
LL | (1..10 + 1).for_each(|_| {});
|
||||||
| ^^^^^^^^^^^ help: use: `(1..=10)`
|
| ^^^^^^^^^ help: use: `1..=10`
|
||||||
|
|
||||||
error: an inclusive range would be more readable
|
error: an inclusive range would be more readable
|
||||||
--> tests/ui/range_plus_minus_one.rs:75:5
|
--> tests/ui/range_plus_minus_one.rs:75:6
|
||||||
|
|
|
|
||||||
LL | (1..10 + 1).into_iter().for_each(|_| {});
|
LL | (1..10 + 1).into_iter().for_each(|_| {});
|
||||||
| ^^^^^^^^^^^ help: use: `(1..=10)`
|
| ^^^^^^^^^ help: use: `1..=10`
|
||||||
|
|
||||||
error: an inclusive range would be more readable
|
error: an inclusive range would be more readable
|
||||||
--> tests/ui/range_plus_minus_one.rs:80:17
|
--> tests/ui/range_plus_minus_one.rs:80:18
|
||||||
|
|
|
|
||||||
LL | let _ = (1..10 + 1).start_bound();
|
LL | let _ = (1..10 + 1).start_bound();
|
||||||
| ^^^^^^^^^^^ help: use: `(1..=10)`
|
| ^^^^^^^^^ help: use: `1..=10`
|
||||||
|
|
||||||
error: an inclusive range would be more readable
|
error: an inclusive range would be more readable
|
||||||
--> tests/ui/range_plus_minus_one.rs:86:16
|
--> tests/ui/range_plus_minus_one.rs:86:16
|
||||||
@@ -80,10 +80,10 @@ LL | a[0..2 + 1][0] = 1;
|
|||||||
| ^^^^^^^^ help: use: `0..=2`
|
| ^^^^^^^^ help: use: `0..=2`
|
||||||
|
|
||||||
error: an exclusive range would be more readable
|
error: an exclusive range would be more readable
|
||||||
--> tests/ui/range_plus_minus_one.rs:180:5
|
--> tests/ui/range_plus_minus_one.rs:180:6
|
||||||
|
|
|
|
||||||
LL | (1..=n - 1).sum()
|
LL | (1..=n - 1).sum()
|
||||||
| ^^^^^^^^^^^ help: use: `(1..n)`
|
| ^^^^^^^^^ help: use: `1..n`
|
||||||
|
|
|
|
||||||
= note: `-D clippy::range-minus-one` implied by `-D warnings`
|
= note: `-D clippy::range-minus-one` implied by `-D warnings`
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::range_minus_one)]`
|
= help: to override `-D warnings` add `#[allow(clippy::range_minus_one)]`
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ const ANSWER: i32 = 42;
|
|||||||
fn main() {
|
fn main() {
|
||||||
// These should be linted:
|
// These should be linted:
|
||||||
|
|
||||||
(21..=42).rev().for_each(|x| println!("{}", x));
|
((21..=42).rev()).for_each(|x| println!("{}", x));
|
||||||
//~^ reversed_empty_ranges
|
//~^ reversed_empty_ranges
|
||||||
let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>();
|
let _ = ((21..ANSWER).rev()).filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>();
|
||||||
//~^ reversed_empty_ranges
|
//~^ reversed_empty_ranges
|
||||||
|
|
||||||
for _ in (-42..=-21).rev() {}
|
for _ in (-42..=-21).rev() {}
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
error: this range is empty so it will yield no values
|
error: this range is empty so it will yield no values
|
||||||
--> tests/ui/reversed_empty_ranges_fixable.rs:9:5
|
--> tests/ui/reversed_empty_ranges_fixable.rs:9:6
|
||||||
|
|
|
|
||||||
LL | (42..=21).for_each(|x| println!("{}", x));
|
LL | (42..=21).for_each(|x| println!("{}", x));
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::reversed-empty-ranges` implied by `-D warnings`
|
= note: `-D clippy::reversed-empty-ranges` implied by `-D warnings`
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::reversed_empty_ranges)]`
|
= help: to override `-D warnings` add `#[allow(clippy::reversed_empty_ranges)]`
|
||||||
help: consider using the following if you are attempting to iterate over this range in reverse
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
||||||
|
|
|
|
||||||
LL - (42..=21).for_each(|x| println!("{}", x));
|
LL - (42..=21).for_each(|x| println!("{}", x));
|
||||||
LL + (21..=42).rev().for_each(|x| println!("{}", x));
|
LL + ((21..=42).rev()).for_each(|x| println!("{}", x));
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this range is empty so it will yield no values
|
error: this range is empty so it will yield no values
|
||||||
--> tests/ui/reversed_empty_ranges_fixable.rs:11:13
|
--> tests/ui/reversed_empty_ranges_fixable.rs:11:14
|
||||||
|
|
|
|
||||||
LL | let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>();
|
LL | let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>();
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
help: consider using the following if you are attempting to iterate over this range in reverse
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
||||||
|
|
|
|
||||||
LL - let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>();
|
LL - let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>();
|
||||||
LL + let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>();
|
LL + let _ = ((21..ANSWER).rev()).filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>();
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this range is empty so it will yield no values
|
error: this range is empty so it will yield no values
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ fn main() {
|
|||||||
println!("{}", i);
|
println!("{}", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in (0..10).rev().map(|x| x * 2) {
|
for i in ((0..10).rev()).map(|x| x * 2) {
|
||||||
//~^ reversed_empty_ranges
|
//~^ reversed_empty_ranges
|
||||||
println!("{}", i);
|
println!("{}", i);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,15 +37,15 @@ LL + for i in (0..MAX_LEN).rev() {
|
|||||||
|
|
|
|
||||||
|
|
||||||
error: this range is empty so it will yield no values
|
error: this range is empty so it will yield no values
|
||||||
--> tests/ui/reversed_empty_ranges_loops_fixable.rs:37:14
|
--> tests/ui/reversed_empty_ranges_loops_fixable.rs:37:15
|
||||||
|
|
|
|
||||||
LL | for i in (10..0).map(|x| x * 2) {
|
LL | for i in (10..0).map(|x| x * 2) {
|
||||||
| ^^^^^^^
|
| ^^^^^
|
||||||
|
|
|
|
||||||
help: consider using the following if you are attempting to iterate over this range in reverse
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
||||||
|
|
|
|
||||||
LL - for i in (10..0).map(|x| x * 2) {
|
LL - for i in (10..0).map(|x| x * 2) {
|
||||||
LL + for i in (0..10).rev().map(|x| x * 2) {
|
LL + for i in ((0..10).rev()).map(|x| x * 2) {
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this range is empty so it will yield no values
|
error: this range is empty so it will yield no values
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
let whatever: [u32; 10] = (0..10).collect();
|
let whatever: [u32; 10] = (0..10).collect();
|
||||||
//~^ ERROR an array of type `[u32; 10]` cannot be built directly from an iterator
|
//~^ ERROR an array of type `[u32; 10]` cannot be built directly from an iterator
|
||||||
|
//~| NOTE required by a bound introduced by this call
|
||||||
//~| NOTE try collecting into a `Vec<{integer}>`, then using `.try_into()`
|
//~| NOTE try collecting into a `Vec<{integer}>`, then using `.try_into()`
|
||||||
//~| NOTE required by a bound in `collect`
|
//~| NOTE required by a bound in `collect`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
error[E0277]: an array of type `[u32; 10]` cannot be built directly from an iterator
|
error[E0277]: an array of type `[u32; 10]` cannot be built directly from an iterator
|
||||||
--> $DIR/collect-into-array.rs:2:39
|
--> $DIR/collect-into-array.rs:2:32
|
||||||
|
|
|
|
||||||
LL | let whatever: [u32; 10] = (0..10).collect();
|
LL | let whatever: [u32; 10] = (0..10).collect();
|
||||||
| ^^^^^^^ try collecting into a `Vec<{integer}>`, then using `.try_into()`
|
| ^^^^^ ------- required by a bound introduced by this call
|
||||||
|
| |
|
||||||
|
| try collecting into a `Vec<{integer}>`, then using `.try_into()`
|
||||||
|
|
|
|
||||||
= help: the trait `FromIterator<{integer}>` is not implemented for `[u32; 10]`
|
= help: the trait `FromIterator<{integer}>` is not implemented for `[u32; 10]`
|
||||||
note: required by a bound in `collect`
|
note: required by a bound in `collect`
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ fn process_slice(data: &[i32]) {
|
|||||||
fn main() {
|
fn main() {
|
||||||
let some_generated_vec = (0..10).collect();
|
let some_generated_vec = (0..10).collect();
|
||||||
//~^ ERROR the size for values of type `[i32]` cannot be known at compilation time
|
//~^ ERROR the size for values of type `[i32]` cannot be known at compilation time
|
||||||
|
//~| NOTE required by a bound introduced by this call
|
||||||
//~| ERROR the size for values of type `[i32]` cannot be known at compilation time
|
//~| ERROR the size for values of type `[i32]` cannot be known at compilation time
|
||||||
//~| ERROR a slice of type `[i32]` cannot be built since `[i32]` has no definite size
|
//~| ERROR a slice of type `[i32]` cannot be built since `[i32]` has no definite size
|
||||||
//~| NOTE try explicitly collecting into a `Vec<{integer}>`
|
//~| NOTE try explicitly collecting into a `Vec<{integer}>`
|
||||||
@@ -17,6 +18,7 @@ fn main() {
|
|||||||
|
|
||||||
let some_generated_vec = (0..10).collect();
|
let some_generated_vec = (0..10).collect();
|
||||||
//~^ ERROR a slice of type `&[i32]` cannot be built since we need to store the elements somewhere
|
//~^ ERROR a slice of type `&[i32]` cannot be built since we need to store the elements somewhere
|
||||||
|
//~| NOTE required by a bound introduced by this call
|
||||||
//~| NOTE try explicitly collecting into a `Vec<{integer}>`
|
//~| NOTE try explicitly collecting into a `Vec<{integer}>`
|
||||||
//~| NOTE required by a bound in `collect`
|
//~| NOTE required by a bound in `collect`
|
||||||
process_slice(some_generated_vec);
|
process_slice(some_generated_vec);
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
error[E0277]: a slice of type `[i32]` cannot be built since `[i32]` has no definite size
|
error[E0277]: a slice of type `[i32]` cannot be built since `[i32]` has no definite size
|
||||||
--> $DIR/collect-into-slice.rs:6:38
|
--> $DIR/collect-into-slice.rs:6:31
|
||||||
|
|
|
|
||||||
LL | let some_generated_vec = (0..10).collect();
|
LL | let some_generated_vec = (0..10).collect();
|
||||||
| ^^^^^^^ try explicitly collecting into a `Vec<{integer}>`
|
| ^^^^^ ------- required by a bound introduced by this call
|
||||||
|
| |
|
||||||
|
| try explicitly collecting into a `Vec<{integer}>`
|
||||||
|
|
|
|
||||||
= help: the trait `FromIterator<{integer}>` is not implemented for `[i32]`
|
= help: the trait `FromIterator<{integer}>` is not implemented for `[i32]`
|
||||||
note: required by a bound in `collect`
|
note: required by a bound in `collect`
|
||||||
@@ -28,10 +30,12 @@ note: required by an implicit `Sized` bound in `collect`
|
|||||||
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
||||||
|
|
||||||
error[E0277]: a slice of type `&[i32]` cannot be built since we need to store the elements somewhere
|
error[E0277]: a slice of type `&[i32]` cannot be built since we need to store the elements somewhere
|
||||||
--> $DIR/collect-into-slice.rs:18:38
|
--> $DIR/collect-into-slice.rs:19:31
|
||||||
|
|
|
|
||||||
LL | let some_generated_vec = (0..10).collect();
|
LL | let some_generated_vec = (0..10).collect();
|
||||||
| ^^^^^^^ try explicitly collecting into a `Vec<{integer}>`
|
| ^^^^^ ------- required by a bound introduced by this call
|
||||||
|
| |
|
||||||
|
| try explicitly collecting into a `Vec<{integer}>`
|
||||||
|
|
|
|
||||||
= help: the trait `FromIterator<{integer}>` is not implemented for `&[i32]`
|
= help: the trait `FromIterator<{integer}>` is not implemented for `&[i32]`
|
||||||
note: required by a bound in `collect`
|
note: required by a bound in `collect`
|
||||||
|
|||||||
@@ -4,4 +4,6 @@ fn main() {
|
|||||||
//~| NOTE expected type `usize`
|
//~| NOTE expected type `usize`
|
||||||
//~| NOTE found struct `RangeTo<{integer}>`
|
//~| NOTE found struct `RangeTo<{integer}>`
|
||||||
//~| NOTE expected `usize`, found `RangeTo<{integer}>
|
//~| NOTE expected `usize`, found `RangeTo<{integer}>
|
||||||
|
//~| NOTE in this expansion of desugaring of range expression
|
||||||
|
//~| NOTE in this expansion of desugaring of range expression
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user