Skip to content

Commit b4bfa81

Browse files
committed
Mark range expr with desugaring
1 parent bd175cb commit b4bfa81

29 files changed

+144
-66
lines changed

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
6262

6363
pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
6464
ensure_sufficient_stack(|| {
65+
let mut span = self.lower_span(e.span);
6566
match &e.kind {
6667
// Parenthesis expression does not have a HirId and is handled specially.
6768
ExprKind::Paren(ex) => {
@@ -287,7 +288,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
287288
self.lower_span(*brackets_span),
288289
),
289290
ExprKind::Range(e1, e2, lims) => {
290-
self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims)
291+
span = self.mark_span_with_reason(DesugaringKind::RangeExpr, span, None);
292+
self.lower_expr_range(span, e1.as_deref(), e2.as_deref(), *lims)
291293
}
292294
ExprKind::Underscore => {
293295
let guar = self.dcx().emit_err(UnderscoreExprLhsAssign { span: e.span });
@@ -379,7 +381,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
379381
ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
380382
};
381383

382-
hir::Expr { hir_id: expr_hir_id, kind, span: self.lower_span(e.span) }
384+
hir::Expr { hir_id: expr_hir_id, kind, span }
383385
})
384386
}
385387

@@ -1505,7 +1507,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
15051507
fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
15061508
let e1 = self.lower_expr_mut(e1);
15071509
let e2 = self.lower_expr_mut(e2);
1508-
let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span));
1510+
let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, span);
15091511
let fn_expr = self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path)));
15101512
hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
15111513
}
@@ -1562,15 +1564,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
15621564
let fields = self.arena.alloc_from_iter(
15631565
e1.iter().map(|e| (sym::start, e)).chain(e2.iter().map(|e| (sym::end, e))).map(
15641566
|(s, e)| {
1567+
let span = self.lower_span(e.span);
1568+
let span = self.mark_span_with_reason(DesugaringKind::RangeExpr, span, None);
15651569
let expr = self.lower_expr(e);
1566-
let ident = Ident::new(s, self.lower_span(e.span));
1567-
self.expr_field(ident, expr, e.span)
1570+
let ident = Ident::new(s, span);
1571+
self.expr_field(ident, expr, span)
15681572
},
15691573
),
15701574
);
15711575

15721576
hir::ExprKind::Struct(
1573-
self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span))),
1577+
self.arena.alloc(hir::QPath::LangItem(lang_item, span)),
15741578
fields,
15751579
hir::StructTailExpr::None,
15761580
)

compiler/rustc_hir/src/hir.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ use rustc_index::IndexVec;
2323
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
2424
use rustc_span::def_id::LocalDefId;
2525
use rustc_span::source_map::Spanned;
26-
use rustc_span::{BytePos, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
26+
use rustc_span::{
27+
BytePos, DUMMY_SP, DesugaringKind, ErrorGuaranteed, Ident, Span, Symbol, kw, sym,
28+
};
2729
use rustc_target::asm::InlineAsmRegOrRegClass;
2830
use smallvec::SmallVec;
2931
use thin_vec::ThinVec;
@@ -2459,6 +2461,18 @@ impl Expr<'_> {
24592461
}
24602462
}
24612463

2464+
/// Returns true if this is a desugared range expression.
2465+
pub fn is_range(&self) -> bool {
2466+
matches!(self.kind, ExprKind::Call(..) | ExprKind::Struct(..))
2467+
&& self.span.desugaring_kind() == Some(DesugaringKind::RangeExpr)
2468+
}
2469+
2470+
/// If this is a desugared range expression,
2471+
/// returns the span of the range without desugaring context.
2472+
pub fn range_span(&self) -> Option<Span> {
2473+
self.is_range().then(|| self.span.parent_callsite().unwrap())
2474+
}
2475+
24622476
/// Check if expression is an integer literal that can be used
24632477
/// where `usize` is expected.
24642478
pub fn is_size_lit(&self) -> bool {
@@ -2694,6 +2708,9 @@ impl Expr<'_> {
26942708
/// Checks if the specified expression is a built-in range literal.
26952709
/// (See: `LoweringContext::lower_expr()`).
26962710
pub fn is_range_literal(expr: &Expr<'_>) -> bool {
2711+
if expr.span.desugaring_kind() != Some(DesugaringKind::RangeExpr) {
2712+
return false;
2713+
}
26972714
match expr.kind {
26982715
// All built-in range literals but `..=` and `..` desugar to `Struct`s.
26992716
ExprKind::Struct(ref qpath, _, _) => matches!(

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2500,11 +2500,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25002500
.tcx
25012501
.sess
25022502
.source_map()
2503-
.span_extend_while_whitespace(range_start.span)
2503+
.span_extend_while_whitespace(range_start.expr.span)
25042504
.shrink_to_hi()
2505-
.to(range_end.span);
2505+
.to(range_end.expr.span);
25062506

2507-
err.subdiagnostic(TypeMismatchFruTypo { expr_span: range_start.span, fru_span, expr });
2507+
err.subdiagnostic(TypeMismatchFruTypo {
2508+
expr_span: range_start.expr.span,
2509+
fru_span,
2510+
expr,
2511+
});
25082512

25092513
// Suppress any range expr type mismatches
25102514
self.dcx().try_steal_replace_and_emit_err(

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1600,25 +1600,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16001600
match expr.kind {
16011601
ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [start, end], _) => {
16021602
err.span_suggestion_verbose(
1603-
start.span.shrink_to_hi().with_hi(end.span.lo()),
1603+
start.expr.span.shrink_to_hi().with_hi(end.expr.span.lo()),
16041604
"remove the unnecessary `.` operator for a floating point literal",
16051605
'.',
16061606
Applicability::MaybeIncorrect,
16071607
);
16081608
true
16091609
}
16101610
ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, ..), [start], _) => {
1611+
let range_span = expr.span.parent_callsite().unwrap();
16111612
err.span_suggestion_verbose(
1612-
expr.span.with_lo(start.span.hi()),
1613+
range_span.with_lo(start.expr.span.hi()),
16131614
"remove the unnecessary `.` operator for a floating point literal",
16141615
'.',
16151616
Applicability::MaybeIncorrect,
16161617
);
16171618
true
16181619
}
16191620
ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, ..), [end], _) => {
1621+
let range_span = expr.span.parent_callsite().unwrap();
16201622
err.span_suggestion_verbose(
1621-
expr.span.until(end.span),
1623+
range_span.until(end.expr.span),
16221624
"remove the unnecessary `.` operator and add an integer part for a floating point literal",
16231625
"0.",
16241626
Applicability::MaybeIncorrect,
@@ -2627,7 +2629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26272629
bool, /* suggest `&` or `&mut` type annotation */
26282630
)> {
26292631
let sess = self.sess();
2630-
let sp = expr.span;
2632+
let sp = expr.range_span().unwrap_or(expr.span);
26312633
let sm = sess.source_map();
26322634

26332635
// If the span is from an external macro, there's no suggestion we can make.

compiler/rustc_lint/src/types/literal.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,13 @@ fn lint_overflowing_range_endpoint<'tcx>(
6666
_ => bug!(),
6767
};
6868

69+
let range_span = struct_expr.span.parent_callsite().unwrap();
6970
let sub_sugg = if span.lo() == lit_span.lo() {
7071
let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else {
7172
return false;
7273
};
7374
UseInclusiveRange::WithoutParen {
74-
sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()),
75+
sugg: range_span.shrink_to_lo().to(lit_span.shrink_to_hi()),
7576
start,
7677
literal: lit_val - 1,
7778
suffix,
@@ -87,7 +88,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
8788

8889
cx.emit_span_lint(
8990
OVERFLOWING_LITERALS,
90-
struct_expr.span,
91+
range_span,
9192
RangeEndpointOutOfRange { ty, sub: sub_sugg },
9293
);
9394

compiler/rustc_span/src/hygiene.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,6 +1237,7 @@ pub enum DesugaringKind {
12371237
/// rewriting it.
12381238
source: bool,
12391239
},
1240+
RangeExpr,
12401241
}
12411242

12421243
impl DesugaringKind {
@@ -1258,6 +1259,7 @@ impl DesugaringKind {
12581259
DesugaringKind::FormatLiteral { source: false } => {
12591260
"expression that expanded into a format string literal"
12601261
}
1262+
DesugaringKind::RangeExpr => "range expression",
12611263
}
12621264
}
12631265

@@ -1277,6 +1279,7 @@ impl DesugaringKind {
12771279
DesugaringKind::Contract => value == "Contract",
12781280
DesugaringKind::PatTyRange => value == "PatTyRange",
12791281
DesugaringKind::FormatLiteral { .. } => value == "FormatLiteral",
1282+
DesugaringKind::RangeExpr => value == "RangeExpr",
12801283
}
12811284
}
12821285
}

src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub(super) fn check<'tcx>(
2727
start: Some(start),
2828
end: Some(end),
2929
limits,
30+
span: _,
3031
}) = higher::Range::hir(arg)
3132
// the var must be a single name
3233
&& let PatKind::Binding(_, canonical_id, _, _) = pat.kind

src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub(super) fn check<'tcx>(
3131
start: Some(start),
3232
end: Some(end),
3333
limits: RangeLimits::HalfOpen,
34+
span: _,
3435
}) = higher::Range::hir(arg)
3536
&& let ExprKind::Lit(Spanned {
3637
node: LitKind::Int(Pu128(0), _),

src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub(super) fn check<'tcx>(
3030
start: Some(start),
3131
ref end,
3232
limits,
33+
span,
3334
}) = higher::Range::hir(arg)
3435
// the var must be a single name
3536
&& let PatKind::Binding(_, canonical_id, ident, _) = pat.kind
@@ -149,15 +150,15 @@ pub(super) fn check<'tcx>(
149150
span_lint_and_then(
150151
cx,
151152
NEEDLESS_RANGE_LOOP,
152-
arg.span,
153+
span,
153154
format!("the loop variable `{}` is used to index `{indexed}`", ident.name),
154155
|diag| {
155156
diag.multipart_suggestion(
156157
"consider using an iterator and enumerate()",
157158
vec![
158159
(pat.span, format!("({}, <item>)", ident.name)),
159160
(
160-
arg.span,
161+
span,
161162
format!("{indexed}.{method}().enumerate(){method_1}{method_2}"),
162163
),
163164
],
@@ -175,12 +176,12 @@ pub(super) fn check<'tcx>(
175176
span_lint_and_then(
176177
cx,
177178
NEEDLESS_RANGE_LOOP,
178-
arg.span,
179+
span,
179180
format!("the loop variable `{}` is only used to index `{indexed}`", ident.name),
180181
|diag| {
181182
diag.multipart_suggestion(
182183
"consider using an iterator",
183-
vec![(pat.span, "<item>".to_string()), (arg.span, repl)],
184+
vec![(pat.span, "<item>".to_string()), (span, repl)],
184185
Applicability::HasPlaceholders,
185186
);
186187
},

src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
108108
start: Some(start),
109109
end: Some(end),
110110
limits: RangeLimits::Closed,
111+
span: _,
111112
}) = higher::Range::hir(receiver)
112113
&& !matches!(cx.typeck_results().expr_ty(arg).peel_refs().kind(), ty::Param(_))
113114
{

0 commit comments

Comments
 (0)