diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 766c120a1f19..ad0c901ede0c 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -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(
)`
- 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()`
- 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],
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 47a1ad0d9489..566da884c194 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -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 in { }`.
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()`
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 `` 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,
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 0b1c725ba408..aff663ba8f59 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -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 {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index dde6b8ce9b8b..2404ec4c706d 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -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,
diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs
index d296ae46f43e..45c32bfd1d5c 100644
--- a/compiler/rustc_lint/src/shadowed_into_iter.rs
+++ b/compiler/rustc_lint/src/shadowed_into_iter.rs
@@ -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()),
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index ac2cc11d3020..5c1a906599d3 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -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;
}
diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout
index 27cba6560300..b5fa442dd247 100644
--- a/tests/ui/unpretty/exhaustive.hir.stdout
+++ b/tests/ui/unpretty/exhaustive.hir.stdout
@@ -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: _ } => { }
}
},
};