Remove QPath::LangItem from for loops

This commit is contained in:
Cameron Steffen 2025-09-01 14:47:40 -05:00
parent 7e51a763c9
commit e289f27329
7 changed files with 54 additions and 29 deletions

View file

@ -1804,7 +1804,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ForLoopKind::For => {
// `Iterator::next(&mut iter)`
let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
self.expr_call_lang_item_qpath_fn(
self.expr_call_lang_item_fn(
head_span,
hir::LangItem::IteratorNext,
arena_vec![self; ref_mut_iter],
@ -1819,7 +1819,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `&mut iter`
let iter = self.expr_mut_addr_of(head_span, iter);
// `Pin::new_unchecked(...)`
let iter = self.arena.alloc(self.expr_call_lang_item_qpath_fn_mut(
let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(
head_span,
hir::LangItem::PinNewUnchecked,
arena_vec![self; iter],
@ -1854,7 +1854,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let match_expr = match loop_kind {
ForLoopKind::For => {
// `::std::iter::IntoIterator::into_iter(<head>)`
let into_iter_expr = self.expr_call_lang_item_qpath_fn(
let into_iter_expr = self.expr_call_lang_item_fn(
head_span,
hir::LangItem::IntoIterIntoIter,
arena_vec![self; head],
@ -1874,7 +1874,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.pat_ident_binding_mode(head_span, iter_ident, hir::BindingMode::REF_MUT);
let iter = self.expr_ident_mut(head_span, iter_ident, async_iter_pat_id);
// `Pin::new_unchecked(...)`
let iter = self.arena.alloc(self.expr_call_lang_item_qpath_fn_mut(
let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(
head_span,
hir::LangItem::PinNewUnchecked,
arena_vec![self; iter],
@ -1889,7 +1889,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
));
// `::core::async_iter::IntoAsyncIterator::into_async_iter(<head>)`
let iter = self.expr_call_lang_item_qpath_fn(
let iter = self.expr_call_lang_item_fn(
head_span,
hir::LangItem::IntoAsyncIterIntoIter,
arena_vec![self; head],

View file

@ -2312,6 +2312,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let typeck_results = tcx.typeck(self.mir_def_id());
struct ExprFinder<'hir> {
tcx: TyCtxt<'hir>,
issue_span: Span,
expr_span: Span,
body_expr: Option<&'hir hir::Expr<'hir>>,
@ -2336,9 +2337,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
// };
// corresponding to the desugaring of a for loop `for <pat> in <head> { <body> }`.
if let hir::ExprKind::Call(path, [arg]) = ex.kind
&& let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IntoIterIntoIter, _)) =
path.kind
&& let hir::ExprKind::Path(qpath) = path.kind
&& self.tcx.qpath_is_lang_item(qpath, LangItem::IntoIterIntoIter)
&& arg.span.contains(self.issue_span)
&& ex.span.desugaring_kind() == Some(DesugaringKind::ForLoop)
{
// Find `IntoIterator::into_iter(<head>)`
self.head = Some(arg);
@ -2355,10 +2357,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
..
}) = stmt.kind
&& let hir::ExprKind::Call(path, _args) = call.kind
&& let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _)) =
path.kind
&& let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind
&& let hir::QPath::LangItem(LangItem::OptionSome, pat_span) = path
&& let hir::ExprKind::Path(qpath) = path.kind
&& self.tcx.qpath_is_lang_item(qpath, LangItem::IteratorNext)
&& let hir::PatKind::Struct(qpath, [field, ..], _) = bind.pat.kind
&& self.tcx.qpath_is_lang_item(qpath, LangItem::OptionSome)
&& call.span.contains(self.issue_span)
{
// Find `<pat>` and the span for the whole `for` loop.
@ -2370,7 +2372,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.loop_bind = Some(ident);
}
self.head_span = Some(*head_span);
self.pat_span = Some(pat_span);
self.pat_span = Some(bind.pat.span);
self.loop_span = Some(stmt.span);
}
@ -2385,6 +2387,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
}
let mut finder = ExprFinder {
tcx,
expr_span: span,
issue_span,
loop_bind: None,

View file

@ -763,6 +763,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
) -> Ty<'tcx> {
let tcx = self.tcx;
if let Some((_, [_arg])) = call_expr_and_args
&& let QPath::Resolved(_, path) = qpath
&& let Res::Def(_, def_id) = path.res
&& let Some(lang_item) = tcx.lang_items().from_def_id(def_id)
{
let code = match lang_item {
LangItem::IntoIterIntoIter | LangItem::IteratorNext
if expr.span.is_desugaring(DesugaringKind::ForLoop) =>
{
Some(ObligationCauseCode::ForLoopIterator)
}
_ => None,
};
if let Some(code) = code {
let args = self.fresh_args_for_item(expr.span, def_id);
self.add_required_obligations_with_code(expr.span, def_id, args, |_, _| {
code.clone()
});
return tcx.type_of(def_id).instantiate(tcx, args);
}
}
let (res, opt_ty, segs) =
self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span);
let ty = match res {

View file

@ -721,9 +721,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None
}
}
hir::LangItem::IteratorNext | hir::LangItem::IntoIterIntoIter => {
Some(ObligationCauseCode::ForLoopIterator)
}
hir::LangItem::TryTraitFromOutput
| hir::LangItem::TryTraitFromResidual
| hir::LangItem::TryTraitBranch => Some(ObligationCauseCode::QuestionMark),
@ -1374,7 +1371,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
#[instrument(level = "debug", skip(self, code, span, args))]
fn add_required_obligations_with_code(
pub(crate) fn add_required_obligations_with_code(
&self,
span: Span,
def_id: DefId,

View file

@ -132,8 +132,8 @@ impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter {
&& let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) =
&parent_expr.kind
&& let hir::ExprKind::Call(path, [_]) = &arg.kind
&& let hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoIterIntoIter, ..)) =
&path.kind
&& let hir::ExprKind::Path(qpath) = path.kind
&& cx.tcx.qpath_is_lang_item(qpath, LangItem::IntoIterIntoIter)
{
Some(ShadowedIntoIterDiagSub::RemoveIntoIter {
span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),

View file

@ -2,7 +2,7 @@ use clippy_config::Conf;
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::{MaybeQPath, MaybeResPath};
use clippy_utils::res::MaybeResPath;
use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::implements_trait;
@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass, Lint};
use rustc_middle::ty::{self, ClauseKind, GenericArgKind, PredicatePolarity, Ty};
use rustc_session::impl_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::{Span, sym};
use rustc_span::{DesugaringKind, Span, sym};
use std::cmp::Ordering;
declare_clippy_lint! {
@ -368,7 +368,9 @@ fn can_switch_ranges<'tcx>(
// Check if `expr` is the argument of a compiler-generated `IntoIter::into_iter(expr)`
if let ExprKind::Call(func, [arg]) = parent_expr.kind
&& arg.hir_id == use_ctxt.child_id
&& func.opt_lang_path() == Some(LangItem::IntoIterIntoIter)
&& let ExprKind::Path(qpath) = func.kind
&& cx.tcx.qpath_is_lang_item(qpath, LangItem::IntoIterIntoIter)
&& parent_expr.span.is_desugaring(DesugaringKind::ForLoop)
{
return true;
}

View file

@ -167,12 +167,12 @@ mod expressions {
let x;
{
let _t =
match #[lang = "into_iter"](x) {
match into_iter(x) {
mut iter =>
loop {
match #[lang = "next"](&mut iter) {
#[lang = "None"] {} => break,
#[lang = "Some"] { 0: _ } => { }
match next(&mut iter) {
None {} => break,
Some { 0: _ } => { }
}
},
};
@ -180,12 +180,12 @@ mod expressions {
};
{
let _t =
match #[lang = "into_iter"](x) {
match into_iter(x) {
mut iter =>
'a: loop {
match #[lang = "next"](&mut iter) {
#[lang = "None"] {} => break,
#[lang = "Some"] { 0: _ } => { }
match next(&mut iter) {
None {} => break,
Some { 0: _ } => { }
}
},
};