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 <mjjasper1@gmail.com> Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
parent
1e2f350d92
commit
664ecf1085
@ -13,7 +13,7 @@ use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::{SourceMap, Spanned};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{MultiSpan, Span, DUMMY_SP};
|
||||
use rustc_target::asm::InlineAsmRegOrRegClass;
|
||||
@ -1495,58 +1495,28 @@ impl Expr<'_> {
|
||||
|
||||
/// Checks if the specified expression is a built-in range literal.
|
||||
/// (See: `LoweringContext::lower_expr()`).
|
||||
///
|
||||
/// FIXME(#60607): This function is a hack. If and when we have `QPath::Lang(...)`,
|
||||
/// we can use that instead as simpler, more reliable mechanism, as opposed to using `SourceMap`.
|
||||
pub fn is_range_literal(sm: &SourceMap, expr: &Expr<'_>) -> bool {
|
||||
// Returns whether the given path represents a (desugared) range,
|
||||
// either in std or core, i.e. has either a `::std::ops::Range` or
|
||||
// `::core::ops::Range` prefix.
|
||||
fn is_range_path(path: &Path<'_>) -> bool {
|
||||
let segs: Vec<_> = path.segments.iter().map(|seg| seg.ident.to_string()).collect();
|
||||
let segs: Vec<_> = segs.iter().map(|seg| &**seg).collect();
|
||||
|
||||
// "{{root}}" is the equivalent of `::` prefix in `Path`.
|
||||
if let ["{{root}}", std_core, "ops", range] = segs.as_slice() {
|
||||
(*std_core == "std" || *std_core == "core") && range.starts_with("Range")
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
// Check whether a span corresponding to a range expression is a
|
||||
// range literal, rather than an explicit struct or `new()` call.
|
||||
fn is_lit(sm: &SourceMap, span: &Span) -> bool {
|
||||
sm.span_to_snippet(*span).map(|range_src| range_src.contains("..")).unwrap_or(false)
|
||||
};
|
||||
|
||||
pub fn is_range_literal(expr: &Expr<'_>) -> bool {
|
||||
match expr.kind {
|
||||
// All built-in range literals but `..=` and `..` desugar to `Struct`s.
|
||||
ExprKind::Struct(ref qpath, _, _) => {
|
||||
if let QPath::Resolved(None, ref path) = **qpath {
|
||||
return is_range_path(&path) && is_lit(sm, &expr.span);
|
||||
}
|
||||
}
|
||||
|
||||
// `..` desugars to its struct path.
|
||||
ExprKind::Path(QPath::Resolved(None, ref path)) => {
|
||||
return is_range_path(&path) && is_lit(sm, &expr.span);
|
||||
}
|
||||
ExprKind::Struct(ref qpath, _, _) => matches!(
|
||||
**qpath,
|
||||
QPath::LangItem(
|
||||
LangItem::Range
|
||||
| LangItem::RangeTo
|
||||
| LangItem::RangeFrom
|
||||
| LangItem::RangeFull
|
||||
| LangItem::RangeToInclusive,
|
||||
_,
|
||||
)
|
||||
),
|
||||
|
||||
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
|
||||
ExprKind::Call(ref func, _) => {
|
||||
if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.kind {
|
||||
if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.kind {
|
||||
let new_call = segment.ident.name == sym::new;
|
||||
return is_range_path(&path) && is_lit(sm, &expr.span) && new_call;
|
||||
}
|
||||
}
|
||||
matches!(func.kind, ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, _)))
|
||||
}
|
||||
|
||||
_ => {}
|
||||
_ => false,
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
#[derive(Debug, HashStable_Generic)]
|
||||
|
@ -258,7 +258,7 @@ fn lint_int_literal<'tcx>(
|
||||
let par_id = cx.tcx.hir().get_parent_node(e.hir_id);
|
||||
if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) {
|
||||
if let hir::ExprKind::Struct(..) = par_e.kind {
|
||||
if is_range_literal(cx.sess().source_map(), par_e)
|
||||
if is_range_literal(par_e)
|
||||
&& lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str())
|
||||
{
|
||||
// The overflowing literal lint was overridden.
|
||||
@ -317,7 +317,7 @@ fn lint_uint_literal<'tcx>(
|
||||
return;
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Struct(..) if is_range_literal(cx.sess().source_map(), par_e) => {
|
||||
hir::ExprKind::Struct(..) if is_range_literal(par_e) => {
|
||||
let t = t.name_str();
|
||||
if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) {
|
||||
// The overflowing literal lint was overridden.
|
||||
|
@ -485,7 +485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// parenthesize if needed (Issue #46756)
|
||||
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
|
||||
// parenthesize borrows of range literals (Issue #54505)
|
||||
_ if is_range_literal(self.tcx.sess.source_map(), expr) => true,
|
||||
_ if is_range_literal(expr) => true,
|
||||
_ => false,
|
||||
};
|
||||
let sugg_expr = if needs_parens { format!("({})", src) } else { src };
|
||||
|
@ -17,9 +17,13 @@ error[E0277]: the size for values of type `[{integer}]` cannot be known at compi
|
||||
|
|
||||
LL | let range = *arr..;
|
||||
| ^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
::: $SRC_DIR/core/src/ops/range.rs:LL:COL
|
||||
|
|
||||
LL | pub struct RangeFrom<Idx> {
|
||||
| --- required by this bound in `std::ops::RangeFrom`
|
||||
|
|
||||
= help: the trait `std::marker::Sized` is not implemented for `[{integer}]`
|
||||
= note: required by `std::ops::RangeFrom`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user