Skip to content

Commit 664ecf1

Browse files
hir: simplify is_range_literal
This commit simplifies `is_range_literal` by checking for `QPath::LangItem` containing range-related lang items, rather than using a heuristic. Co-authored-by: Matthew Jasper <[email protected]> Signed-off-by: David Wood <[email protected]>
1 parent 1e2f350 commit 664ecf1

File tree

4 files changed

+23
-49
lines changed

4 files changed

+23
-49
lines changed

src/librustc_hir/hir.rs

+15-45
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_ast::util::parser::ExprPrecedence;
1313
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
1414
use rustc_macros::HashStable_Generic;
1515
use rustc_span::def_id::LocalDefId;
16-
use rustc_span::source_map::{SourceMap, Spanned};
16+
use rustc_span::source_map::Spanned;
1717
use rustc_span::symbol::{kw, sym, Ident, Symbol};
1818
use rustc_span::{MultiSpan, Span, DUMMY_SP};
1919
use rustc_target::asm::InlineAsmRegOrRegClass;
@@ -1495,58 +1495,28 @@ impl Expr<'_> {
14951495

14961496
/// Checks if the specified expression is a built-in range literal.
14971497
/// (See: `LoweringContext::lower_expr()`).
1498-
///
1499-
/// FIXME(#60607): This function is a hack. If and when we have `QPath::Lang(...)`,
1500-
/// we can use that instead as simpler, more reliable mechanism, as opposed to using `SourceMap`.
1501-
pub fn is_range_literal(sm: &SourceMap, expr: &Expr<'_>) -> bool {
1502-
// Returns whether the given path represents a (desugared) range,
1503-
// either in std or core, i.e. has either a `::std::ops::Range` or
1504-
// `::core::ops::Range` prefix.
1505-
fn is_range_path(path: &Path<'_>) -> bool {
1506-
let segs: Vec<_> = path.segments.iter().map(|seg| seg.ident.to_string()).collect();
1507-
let segs: Vec<_> = segs.iter().map(|seg| &**seg).collect();
1508-
1509-
// "{{root}}" is the equivalent of `::` prefix in `Path`.
1510-
if let ["{{root}}", std_core, "ops", range] = segs.as_slice() {
1511-
(*std_core == "std" || *std_core == "core") && range.starts_with("Range")
1512-
} else {
1513-
false
1514-
}
1515-
};
1516-
1517-
// Check whether a span corresponding to a range expression is a
1518-
// range literal, rather than an explicit struct or `new()` call.
1519-
fn is_lit(sm: &SourceMap, span: &Span) -> bool {
1520-
sm.span_to_snippet(*span).map(|range_src| range_src.contains("..")).unwrap_or(false)
1521-
};
1522-
1498+
pub fn is_range_literal(expr: &Expr<'_>) -> bool {
15231499
match expr.kind {
15241500
// All built-in range literals but `..=` and `..` desugar to `Struct`s.
1525-
ExprKind::Struct(ref qpath, _, _) => {
1526-
if let QPath::Resolved(None, ref path) = **qpath {
1527-
return is_range_path(&path) && is_lit(sm, &expr.span);
1528-
}
1529-
}
1530-
1531-
// `..` desugars to its struct path.
1532-
ExprKind::Path(QPath::Resolved(None, ref path)) => {
1533-
return is_range_path(&path) && is_lit(sm, &expr.span);
1534-
}
1501+
ExprKind::Struct(ref qpath, _, _) => matches!(
1502+
**qpath,
1503+
QPath::LangItem(
1504+
LangItem::Range
1505+
| LangItem::RangeTo
1506+
| LangItem::RangeFrom
1507+
| LangItem::RangeFull
1508+
| LangItem::RangeToInclusive,
1509+
_,
1510+
)
1511+
),
15351512

15361513
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
15371514
ExprKind::Call(ref func, _) => {
1538-
if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.kind {
1539-
if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.kind {
1540-
let new_call = segment.ident.name == sym::new;
1541-
return is_range_path(&path) && is_lit(sm, &expr.span) && new_call;
1542-
}
1543-
}
1515+
matches!(func.kind, ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, _)))
15441516
}
15451517

1546-
_ => {}
1518+
_ => false,
15471519
}
1548-
1549-
false
15501520
}
15511521

15521522
#[derive(Debug, HashStable_Generic)]

src/librustc_lint/types.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ fn lint_int_literal<'tcx>(
258258
let par_id = cx.tcx.hir().get_parent_node(e.hir_id);
259259
if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) {
260260
if let hir::ExprKind::Struct(..) = par_e.kind {
261-
if is_range_literal(cx.sess().source_map(), par_e)
261+
if is_range_literal(par_e)
262262
&& lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str())
263263
{
264264
// The overflowing literal lint was overridden.
@@ -317,7 +317,7 @@ fn lint_uint_literal<'tcx>(
317317
return;
318318
}
319319
}
320-
hir::ExprKind::Struct(..) if is_range_literal(cx.sess().source_map(), par_e) => {
320+
hir::ExprKind::Struct(..) if is_range_literal(par_e) => {
321321
let t = t.name_str();
322322
if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) {
323323
// The overflowing literal lint was overridden.

src/librustc_typeck/check/demand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
485485
// parenthesize if needed (Issue #46756)
486486
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
487487
// parenthesize borrows of range literals (Issue #54505)
488-
_ if is_range_literal(self.tcx.sess.source_map(), expr) => true,
488+
_ if is_range_literal(expr) => true,
489489
_ => false,
490490
};
491491
let sugg_expr = if needs_parens { format!("({})", src) } else { src };

src/test/ui/range/range-1.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,13 @@ error[E0277]: the size for values of type `[{integer}]` cannot be known at compi
1717
|
1818
LL | let range = *arr..;
1919
| ^^^^^^ doesn't have a size known at compile-time
20+
|
21+
::: $SRC_DIR/core/src/ops/range.rs:LL:COL
22+
|
23+
LL | pub struct RangeFrom<Idx> {
24+
| --- required by this bound in `std::ops::RangeFrom`
2025
|
2126
= help: the trait `std::marker::Sized` is not implemented for `[{integer}]`
22-
= note: required by `std::ops::RangeFrom`
2327

2428
error: aborting due to 3 previous errors
2529

0 commit comments

Comments
 (0)