Auto merge of #148193 - camsteffen:remove-qpath-langitem, r=cjgillot

Remove `QPath::LangItem`

Closes rust-lang/rust#115178.

r? cjgillot
This commit is contained in:
bors
2025-10-30 10:04:21 +00:00
76 changed files with 326 additions and 477 deletions

View File

@@ -1,3 +1,5 @@
use std::sync::Arc;
use thin_vec::thin_vec;
use crate::LoweringContext;
@@ -128,7 +130,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let req_span = self.mark_span_with_reason(
rustc_span::DesugaringKind::Contract,
lowered_req.span,
None,
Some(Arc::clone(&self.allow_contracts)),
);
let precond = self.expr_call_lang_item_fn_mut(
req_span,
@@ -143,8 +145,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ens: &Box<rustc_ast::Expr>,
) -> &'hir rustc_hir::Expr<'hir> {
let ens_span = self.lower_span(ens.span);
let ens_span =
self.mark_span_with_reason(rustc_span::DesugaringKind::Contract, ens_span, None);
let ens_span = self.mark_span_with_reason(
rustc_span::DesugaringKind::Contract,
ens_span,
Some(Arc::clone(&self.allow_contracts)),
);
let lowered_ens = self.lower_expr_mut(&ens);
self.expr_call_lang_item_fn(
ens_span,

View File

@@ -865,6 +865,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
};
let features = match await_kind {
FutureKind::Future if is_async_gen => Some(Arc::clone(&self.allow_async_gen)),
FutureKind::Future => None,
FutureKind::AsyncIterator => Some(Arc::clone(&self.allow_for_await)),
};
@@ -1479,7 +1480,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
let e1 = self.lower_expr_mut(e1);
let e2 = self.lower_expr_mut(e2);
let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, span);
let fn_path = self.make_lang_item_qpath(hir::LangItem::RangeInclusiveNew, span, None);
let fn_expr = self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path)));
hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
}
@@ -1565,7 +1566,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
hir::ExprKind::Struct(
self.arena.alloc(hir::QPath::LangItem(lang_item, span)),
self.arena.alloc(self.make_lang_item_qpath(lang_item, span, None)),
fields,
hir::StructTailExpr::None,
)
@@ -1715,8 +1716,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `yield $expr` is transformed into `task_context = yield async_gen_ready($expr)`.
// This ensures that we store our resumed `ResumeContext` correctly, and also that
// the apparent value of the `yield` expression is `()`.
let wrapped_yielded = self.expr_call_lang_item_fn(
let desugar_span = self.mark_span_with_reason(
DesugaringKind::Async,
span,
Some(Arc::clone(&self.allow_async_gen)),
);
let wrapped_yielded = self.expr_call_lang_item_fn(
desugar_span,
hir::LangItem::AsyncGenReady,
std::slice::from_ref(yielded),
);
@@ -1728,7 +1734,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
unreachable!("use of `await` outside of an async context.");
};
let task_context_ident = Ident::with_dummy_span(sym::_task_context);
let lhs = self.expr_ident(span, task_context_ident, task_context_hid);
let lhs = self.expr_ident(desugar_span, task_context_ident, task_context_hid);
hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span))
} else {
@@ -2161,7 +2167,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
lang_item: hir::LangItem,
fields: &'hir [hir::Expr<'hir>],
) -> hir::Expr<'hir> {
let path = self.arena.alloc(self.lang_item_path(span, lang_item));
let path = self.arena.alloc(self.make_lang_item_qpath(lang_item, span, None));
self.expr_enum_variant(span, path, fields)
}
@@ -2198,16 +2204,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
span: Span,
lang_item: hir::LangItem,
) -> hir::Expr<'hir> {
let path = self.lang_item_path(span, lang_item);
self.expr(span, hir::ExprKind::Path(path))
}
pub(super) fn lang_item_path(
&mut self,
span: Span,
lang_item: hir::LangItem,
) -> hir::QPath<'hir> {
hir::QPath::LangItem(lang_item, self.lower_span(span))
let qpath = self.make_lang_item_qpath(lang_item, self.lower_span(span), None);
self.expr(span, hir::ExprKind::Path(qpath))
}
/// `<LangItem>::name`

View File

@@ -391,7 +391,8 @@ fn make_format_spec<'hir>(
let flags = ctx.expr_field(Ident::new(sym::flags, sp), ctx.arena.alloc(flags), sp);
let precision = ctx.expr_field(Ident::new(sym::precision, sp), ctx.arena.alloc(precision), sp);
let width = ctx.expr_field(Ident::new(sym::width, sp), ctx.arena.alloc(width), sp);
let placeholder = ctx.arena.alloc(hir::QPath::LangItem(hir::LangItem::FormatPlaceholder, sp));
let placeholder =
ctx.arena.alloc(ctx.make_lang_item_qpath(hir::LangItem::FormatPlaceholder, sp, None));
let fields = ctx.arena.alloc_from_iter([position, flags, precision, width]);
ctx.expr(sp, hir::ExprKind::Struct(placeholder, fields, hir::StructTailExpr::None))
}

View File

@@ -138,9 +138,11 @@ struct LoweringContext<'a, 'hir> {
#[cfg(debug_assertions)]
node_id_to_local_id: NodeMap<hir::ItemLocalId>,
allow_contracts: Arc<[Symbol]>,
allow_try_trait: Arc<[Symbol]>,
allow_gen_future: Arc<[Symbol]>,
allow_pattern_type: Arc<[Symbol]>,
allow_async_gen: Arc<[Symbol]>,
allow_async_iterator: Arc<[Symbol]>,
allow_for_await: Arc<[Symbol]>,
allow_async_fn_traits: Arc<[Symbol]>,
@@ -183,6 +185,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
current_item: None,
impl_trait_defs: Vec::new(),
impl_trait_bounds: Vec::new(),
allow_contracts: [sym::contracts_internals].into(),
allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(),
allow_pattern_type: [sym::pattern_types, sym::pattern_type_range_trait].into(),
allow_gen_future: if tcx.features().async_fn_track_caller() {
@@ -190,8 +193,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} else {
[sym::gen_future].into()
},
allow_for_await: [sym::async_iterator].into(),
allow_for_await: [sym::async_gen_internals, sym::async_iterator].into(),
allow_async_fn_traits: [sym::async_fn_traits].into(),
allow_async_gen: [sym::async_gen_internals].into(),
// FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller`
// interact with `gen`/`async gen` blocks
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
@@ -2531,8 +2535,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
lang_item: hir::LangItem,
fields: &'hir [hir::PatField<'hir>],
) -> &'hir hir::Pat<'hir> {
let qpath = hir::QPath::LangItem(lang_item, self.lower_span(span));
self.pat(span, hir::PatKind::Struct(qpath, fields, None))
let path = self.make_lang_item_qpath(lang_item, self.lower_span(span), None);
self.pat(span, hir::PatKind::Struct(path, fields, None))
}
fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, HirId) {

View File

@@ -503,8 +503,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
if let hir::Node::Expr(parent_expr) = parent
&& let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
&& let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IntoIterIntoIter, _)) =
call_expr.kind
&& let hir::ExprKind::Path(qpath) = call_expr.kind
&& tcx.qpath_is_lang_item(qpath, LangItem::IntoIterIntoIter)
{
// Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
} else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } = move_spans
@@ -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

@@ -23,13 +23,14 @@ use rustc_index::IndexVec;
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::Spanned;
use rustc_span::{BytePos, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
use rustc_span::{
BytePos, DUMMY_SP, DesugaringKind, ErrorGuaranteed, Ident, Span, Symbol, kw, sym,
};
use rustc_target::asm::InlineAsmRegOrRegClass;
use smallvec::SmallVec;
use thin_vec::ThinVec;
use tracing::debug;
use crate::LangItem;
use crate::attrs::AttributeKind;
use crate::def::{CtorKind, DefKind, MacroKinds, PerNS, Res};
use crate::def_id::{DefId, LocalDefIdMap};
@@ -2418,9 +2419,6 @@ impl Expr<'_> {
allow_projections_from(base) || base.is_place_expr(allow_projections_from)
}
// Lang item paths cannot currently be local variables or statics.
ExprKind::Path(QPath::LangItem(..)) => false,
// Suppress errors for bad expressions.
ExprKind::Err(_guar)
| ExprKind::Let(&LetExpr { recovered: ast::Recovered::Yes(_guar), .. }) => true,
@@ -2590,112 +2588,27 @@ impl Expr<'_> {
pub fn equivalent_for_indexing(&self, other: &Expr<'_>) -> bool {
match (self.kind, other.kind) {
(ExprKind::Lit(lit1), ExprKind::Lit(lit2)) => lit1.node == lit2.node,
(
ExprKind::Path(QPath::LangItem(item1, _)),
ExprKind::Path(QPath::LangItem(item2, _)),
) => item1 == item2,
(
ExprKind::Path(QPath::Resolved(None, path1)),
ExprKind::Path(QPath::Resolved(None, path2)),
) => path1.res == path2.res,
(
ExprKind::Struct(
QPath::LangItem(LangItem::RangeTo, _),
[val1],
&QPath::Resolved(None, &Path { res: Res::Def(_, path1_def_id), .. }),
args1,
StructTailExpr::None,
),
ExprKind::Struct(
QPath::LangItem(LangItem::RangeTo, _),
[val2],
StructTailExpr::None,
),
)
| (
ExprKind::Struct(
QPath::LangItem(LangItem::RangeToInclusive, _),
[val1],
StructTailExpr::None,
),
ExprKind::Struct(
QPath::LangItem(LangItem::RangeToInclusive, _),
[val2],
StructTailExpr::None,
),
)
| (
ExprKind::Struct(
QPath::LangItem(LangItem::RangeToInclusiveCopy, _),
[val1],
StructTailExpr::None,
),
ExprKind::Struct(
QPath::LangItem(LangItem::RangeToInclusiveCopy, _),
[val2],
StructTailExpr::None,
),
)
| (
ExprKind::Struct(
QPath::LangItem(LangItem::RangeFrom, _),
[val1],
StructTailExpr::None,
),
ExprKind::Struct(
QPath::LangItem(LangItem::RangeFrom, _),
[val2],
StructTailExpr::None,
),
)
| (
ExprKind::Struct(
QPath::LangItem(LangItem::RangeFromCopy, _),
[val1],
StructTailExpr::None,
),
ExprKind::Struct(
QPath::LangItem(LangItem::RangeFromCopy, _),
[val2],
StructTailExpr::None,
),
) => val1.expr.equivalent_for_indexing(val2.expr),
(
ExprKind::Struct(
QPath::LangItem(LangItem::Range, _),
[val1, val3],
StructTailExpr::None,
),
ExprKind::Struct(
QPath::LangItem(LangItem::Range, _),
[val2, val4],
StructTailExpr::None,
),
)
| (
ExprKind::Struct(
QPath::LangItem(LangItem::RangeCopy, _),
[val1, val3],
StructTailExpr::None,
),
ExprKind::Struct(
QPath::LangItem(LangItem::RangeCopy, _),
[val2, val4],
StructTailExpr::None,
),
)
| (
ExprKind::Struct(
QPath::LangItem(LangItem::RangeInclusiveCopy, _),
[val1, val3],
StructTailExpr::None,
),
ExprKind::Struct(
QPath::LangItem(LangItem::RangeInclusiveCopy, _),
[val2, val4],
&QPath::Resolved(None, &Path { res: Res::Def(_, path2_def_id), .. }),
args2,
StructTailExpr::None,
),
) => {
val1.expr.equivalent_for_indexing(val2.expr)
&& val3.expr.equivalent_for_indexing(val4.expr)
path2_def_id == path1_def_id
&& is_range_literal(self)
&& is_range_literal(other)
&& std::iter::zip(args1, args2)
.all(|(a, b)| a.expr.equivalent_for_indexing(b.expr))
}
_ => false,
}
@@ -2713,30 +2626,29 @@ impl Expr<'_> {
/// Checks if the specified expression is a built-in range literal.
/// (See: `LoweringContext::lower_expr()`).
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, _, _) => matches!(
**qpath,
QPath::LangItem(
LangItem::Range
| LangItem::RangeTo
| LangItem::RangeFrom
| LangItem::RangeFull
| LangItem::RangeToInclusive
| LangItem::RangeCopy
| LangItem::RangeFromCopy
| LangItem::RangeInclusiveCopy
| LangItem::RangeToInclusiveCopy,
..
)
),
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
ExprKind::Call(ref func, _) => {
matches!(func.kind, ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)))
}
_ => false,
if let ExprKind::Struct(QPath::Resolved(None, path), _, StructTailExpr::None) = expr.kind
&& let [.., segment] = path.segments
&& let sym::RangeFrom
| sym::RangeFull
| sym::Range
| sym::RangeToInclusive
| sym::RangeTo
| sym::RangeFromCopy
| sym::RangeCopy
| sym::RangeInclusiveCopy
| sym::RangeToInclusiveCopy = segment.ident.name
&& expr.span.is_desugaring(DesugaringKind::RangeExpr)
{
true
} else if let ExprKind::Call(func, _) = &expr.kind
&& let ExprKind::Path(QPath::Resolved(None, path)) = func.kind
&& let [.., segment] = path.segments
&& let sym::range_inclusive_new = segment.ident.name
&& expr.span.is_desugaring(DesugaringKind::RangeExpr)
{
true
} else {
false
}
}
@@ -2930,9 +2842,6 @@ pub enum QPath<'hir> {
/// `<Vec>::new`, and `T::X::Y::method` into `<<<T>::X>::Y>::method`,
/// the `X` and `Y` nodes each being a `TyKind::Path(QPath::TypeRelative(..))`.
TypeRelative(&'hir Ty<'hir>, &'hir PathSegment<'hir>),
/// Reference to a `#[lang = "foo"]` item.
LangItem(LangItem, Span),
}
impl<'hir> QPath<'hir> {
@@ -2941,7 +2850,6 @@ impl<'hir> QPath<'hir> {
match *self {
QPath::Resolved(_, path) => path.span,
QPath::TypeRelative(qself, ps) => qself.span.to(ps.ident.span),
QPath::LangItem(_, span) => span,
}
}
@@ -2951,7 +2859,6 @@ impl<'hir> QPath<'hir> {
match *self {
QPath::Resolved(_, path) => path.span,
QPath::TypeRelative(qself, _) => qself.span,
QPath::LangItem(_, span) => span,
}
}
}

View File

@@ -1416,7 +1416,6 @@ pub fn walk_qpath<'v, V: Visitor<'v>>(
try_visit!(visitor.visit_ty_unambig(qself));
visitor.visit_path_segment(segment)
}
QPath::LangItem(..) => V::Result::output(),
}
}

View File

@@ -2240,13 +2240,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
.unwrap_or_else(|guar| Const::new_error(tcx, guar))
}
hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => {
ty::Const::new_error_with_message(
tcx,
qpath.span(),
format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
)
}
hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon),
hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
}
@@ -2561,17 +2554,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.map(|(ty, _, _)| ty)
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
}
&hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => {
let def_id = tcx.require_lang_item(lang_item, span);
let (args, _) = self.lower_generic_args_of_path(
span,
def_id,
&[],
&hir::PathSegment::invalid(),
None,
);
tcx.at(span).type_of(def_id).instantiate(tcx, args)
}
hir::TyKind::Array(ty, length) => {
let length = self.lower_const_arg(length, FeedConstTy::No);
Ty::new_array_with_const_len(tcx, self.lower_ty(ty), length)

View File

@@ -1774,11 +1774,6 @@ impl<'a> State<'a> {
self.print_ident(item_segment.ident);
self.print_generic_args(item_segment.args(), colons_before_params)
}
hir::QPath::LangItem(lang_item, span) => {
self.word("#[lang = \"");
self.print_ident(Ident::new(lang_item.name(), span));
self.word("\"]");
}
}
}

View File

@@ -1196,6 +1196,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(expr.hir_id) else {
return;
};
if parent_expr.span.desugaring_kind().is_some() {
return;
}
enum CallableKind {
Function,
Method,

View File

@@ -19,7 +19,7 @@ use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, HirId, QPath, find_attr};
use rustc_hir::{ExprKind, HirId, QPath, find_attr, is_range_literal};
use rustc_hir_analysis::NoVariantNamed;
use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _};
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, RegionVariableOrigin};
@@ -545,9 +545,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ExprKind::AddrOf(kind, mutbl, oprnd) => {
self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
}
ExprKind::Path(QPath::LangItem(lang_item, _)) => {
self.check_lang_item_path(lang_item, expr)
}
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None),
ExprKind::InlineAsm(asm) => {
// We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars).
@@ -748,14 +745,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
fn check_lang_item_path(
&self,
lang_item: hir::LangItem,
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1
}
pub(crate) fn check_expr_path(
&self,
qpath: &'tcx hir::QPath<'tcx>,
@@ -763,6 +752,45 @@ 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::IntoFutureIntoFuture
if expr.span.is_desugaring(DesugaringKind::Await) =>
{
Some(ObligationCauseCode::AwaitableExpr(arg.hir_id))
}
LangItem::IntoIterIntoIter | LangItem::IteratorNext
if expr.span.is_desugaring(DesugaringKind::ForLoop) =>
{
Some(ObligationCauseCode::ForLoopIterator)
}
LangItem::TryTraitFromOutput
if expr.span.is_desugaring(DesugaringKind::TryBlock) =>
{
// FIXME it's a try block, not a question mark
Some(ObligationCauseCode::QuestionMark)
}
LangItem::TryTraitBranch | LangItem::TryTraitFromResidual
if expr.span.is_desugaring(DesugaringKind::QuestionMark) =>
{
Some(ObligationCauseCode::QuestionMark)
}
_ => 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 {
@@ -2483,9 +2511,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
args: GenericArgsRef<'tcx>,
mut err: Diag<'_>,
) {
// I don't use 'is_range_literal' because only double-sided, half-open ranges count.
if let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [range_start, range_end], _) =
last_expr_field.expr.kind
if is_range_literal(last_expr_field.expr)
&& let ExprKind::Struct(&qpath, [range_start, range_end], _) = last_expr_field.expr.kind
&& self.tcx.qpath_is_lang_item(qpath, LangItem::Range)
&& let variant_field =
variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident)
&& let range_def_id = self.tcx.lang_items().range_struct()

View File

@@ -671,9 +671,6 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
path.segments.last().expect("paths should have a segment")
}
hir::QPath::TypeRelative(_, segment) => segment,
hir::QPath::LangItem(..) => {
return hir::intravisit::walk_qpath(self, qpath, id);
}
};
// Alternatively, try to turbofish `::<_, (), _>`.
if let Some(def_id) = self.fcx.typeck_results.borrow().qpath_res(qpath, id).opt_def_id()

View File

@@ -691,53 +691,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
vec![ty_error; len]
}
pub(crate) fn resolve_lang_item_path(
&self,
lang_item: hir::LangItem,
span: Span,
hir_id: HirId,
) -> (Res, Ty<'tcx>) {
let def_id = self.tcx.require_lang_item(lang_item, span);
let def_kind = self.tcx.def_kind(def_id);
let item_ty = if let DefKind::Variant = def_kind {
self.tcx.type_of(self.tcx.parent(def_id))
} else {
self.tcx.type_of(def_id)
};
let args = self.fresh_args_for_item(span, def_id);
let ty = item_ty.instantiate(self.tcx, args);
self.write_args(hir_id, args);
self.write_resolution(hir_id, Ok((def_kind, def_id)));
let code = match lang_item {
hir::LangItem::IntoFutureIntoFuture => {
if let hir::Node::Expr(into_future_call) = self.tcx.parent_hir_node(hir_id)
&& let hir::ExprKind::Call(_, [arg0]) = &into_future_call.kind
{
Some(ObligationCauseCode::AwaitableExpr(arg0.hir_id))
} else {
None
}
}
hir::LangItem::IteratorNext | hir::LangItem::IntoIterIntoIter => {
Some(ObligationCauseCode::ForLoopIterator)
}
hir::LangItem::TryTraitFromOutput
| hir::LangItem::TryTraitFromResidual
| hir::LangItem::TryTraitBranch => Some(ObligationCauseCode::QuestionMark),
_ => None,
};
if let Some(code) = code {
self.add_required_obligations_with_code(span, def_id, args, move |_, _| code.clone());
} else {
self.add_required_obligations_for_hir(span, def_id, args, hir_id);
}
(Res::Def(def_kind, def_id), ty)
}
/// Resolves an associated value path into a base type and associated constant, or method
/// resolution. The newly resolved definition is written into `type_dependent_defs`.
#[instrument(level = "trace", skip(self), ret)]
@@ -768,9 +721,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.lowerer().lower_ty(qself);
(LoweredTy::from_raw(self, span, ty), qself, segment)
}
QPath::LangItem(..) => {
bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`")
}
};
self.register_wf_obligation(
@@ -1035,8 +985,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// inherent impl, we need to record the
// `T` for posterity (see `UserSelfTy` for
// details).
let self_ty = self_ty.expect("UFCS sugared assoc missing Self").raw;
user_self_ty = Some(UserSelfTy { impl_def_id: container_id, self_ty });
// Generated desugaring code may have a path without a self.
user_self_ty = self_ty.map(|self_ty| UserSelfTy {
impl_def_id: container_id,
self_ty: self_ty.raw,
});
}
}
}
@@ -1374,7 +1327,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

@@ -419,7 +419,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return true;
}
}
_ => {}
}
false

View File

@@ -8,7 +8,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, a_or_an, lis
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath};
use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath, is_range_literal};
use rustc_hir_analysis::check::potentially_plural_count;
use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants};
use rustc_index::IndexVec;
@@ -1290,10 +1290,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty)
}
QPath::LangItem(lang_item, span) => {
let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id);
(res, LoweredTy::from_raw(self, path_span, ty))
}
}
}
@@ -2051,8 +2047,9 @@ impl<'a, 'b, 'tcx> FnCallDiagCtxt<'a, 'b, 'tcx> {
fn detect_dotdot(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, expr: &hir::Expr<'tcx>) {
if let ty::Adt(adt, _) = ty.kind()
&& self.tcx().is_lang_item(adt.did(), hir::LangItem::RangeFull)
&& let hir::ExprKind::Struct(hir::QPath::LangItem(hir::LangItem::RangeFull, _), [], _) =
expr.kind
&& is_range_literal(expr)
&& let hir::ExprKind::Struct(&path, [], _) = expr.kind
&& self.tcx().qpath_is_lang_item(path, hir::LangItem::RangeFull)
{
// We have `Foo(a, .., c)`, where the user might be trying to use the "rest" syntax
// from default field values, which is not supported on tuples.

View File

@@ -11,7 +11,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir::{
self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind,
GenericBound, HirId, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, TyKind,
WherePredicateKind, expr_needs_parens,
WherePredicateKind, expr_needs_parens, is_range_literal,
};
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_hir_analysis::suggest_impl_trait;
@@ -1664,7 +1664,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return false;
}
match expr.kind {
ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [start, end], _) => {
ExprKind::Struct(&qpath, [start, end], _)
if is_range_literal(expr)
&& self.tcx.qpath_is_lang_item(qpath, LangItem::Range) =>
{
err.span_suggestion_verbose(
start.expr.span.shrink_to_hi().with_hi(end.expr.span.lo()),
"remove the unnecessary `.` operator for a floating point literal",
@@ -1673,24 +1676,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
true
}
ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, ..), [start], _) => {
ExprKind::Struct(&qpath, [arg], _)
if is_range_literal(expr)
&& let Some(qpath @ (LangItem::RangeFrom | LangItem::RangeTo)) =
self.tcx.qpath_lang_item(qpath) =>
{
let range_span = expr.span.parent_callsite().unwrap();
err.span_suggestion_verbose(
range_span.with_lo(start.expr.span.hi()),
"remove the unnecessary `.` operator for a floating point literal",
'.',
Applicability::MaybeIncorrect,
);
true
}
ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, ..), [end], _) => {
let range_span = expr.span.parent_callsite().unwrap();
err.span_suggestion_verbose(
range_span.until(end.expr.span),
"remove the unnecessary `.` operator and add an integer part for a floating point literal",
"0.",
Applicability::MaybeIncorrect,
);
match qpath {
LangItem::RangeFrom => {
err.span_suggestion_verbose(
range_span.with_lo(arg.expr.span.hi()),
"remove the unnecessary `.` operator for a floating point literal",
'.',
Applicability::MaybeIncorrect,
);
}
_ => {
err.span_suggestion_verbose(
range_span.until(arg.expr.span),
"remove the unnecessary `.` operator and add an integer part for a floating point literal",
"0.",
Applicability::MaybeIncorrect,
);
}
}
true
}
ExprKind::Lit(Spanned {
@@ -3497,11 +3506,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !hir::is_range_literal(expr) {
return;
}
let hir::ExprKind::Struct(hir::QPath::LangItem(LangItem::Range, ..), [start, end], _) =
expr.kind
else {
let hir::ExprKind::Struct(&qpath, [start, end], _) = expr.kind else {
return;
};
if !self.tcx.qpath_is_lang_item(qpath, LangItem::Range) {
return;
}
if let hir::Node::ExprField(_) = self.tcx.parent_hir_node(expr.hir_id) {
// Ignore `Foo { field: a..Default::default() }`
return;

View File

@@ -19,7 +19,9 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{self as hir, ExprKind, HirId, Node, PathSegment, QPath, find_attr};
use rustc_hir::{
self as hir, ExprKind, HirId, Node, PathSegment, QPath, find_attr, is_range_literal,
};
use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin};
use rustc_middle::bug;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type};
@@ -2412,22 +2414,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let SelfSource::MethodCall(expr) = source {
for (_, parent) in tcx.hir_parent_iter(expr.hir_id).take(5) {
if let Node::Expr(parent_expr) = parent {
if !is_range_literal(parent_expr) {
continue;
}
let lang_item = match parent_expr.kind {
ExprKind::Struct(qpath, _, _) => match *qpath {
QPath::LangItem(LangItem::Range, ..) => Some(LangItem::Range),
QPath::LangItem(LangItem::RangeCopy, ..) => Some(LangItem::RangeCopy),
QPath::LangItem(LangItem::RangeInclusiveCopy, ..) => {
Some(LangItem::RangeInclusiveCopy)
}
QPath::LangItem(LangItem::RangeTo, ..) => Some(LangItem::RangeTo),
QPath::LangItem(LangItem::RangeToInclusive, ..) => {
Some(LangItem::RangeToInclusive)
}
ExprKind::Struct(qpath, _, _) => match tcx.qpath_lang_item(*qpath) {
Some(
lang_item @ (LangItem::Range
| LangItem::RangeCopy
| LangItem::RangeInclusiveCopy
| LangItem::RangeTo
| LangItem::RangeToInclusive),
) => Some(lang_item),
_ => None,
},
ExprKind::Call(func, _) => match func.kind {
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) => {
ExprKind::Path(qpath)
if tcx.qpath_is_lang_item(qpath, LangItem::RangeInclusiveNew) =>
{
Some(LangItem::RangeInclusiveStruct)
}
_ => None,

View File

@@ -718,7 +718,7 @@ impl<'tcx> LateContext<'tcx> {
pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
match *qpath {
hir::QPath::Resolved(_, path) => path.res,
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
hir::QPath::TypeRelative(..) => self
.maybe_typeck_results()
.filter(|typeck_results| typeck_results.hir_owner == id.owner)
.or_else(|| {

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

@@ -2598,8 +2598,6 @@ pub fn rendered_const<'tcx>(tcx: TyCtxt<'tcx>, body: &hir::Body<'_>, def_id: Loc
// FIXME: Claiming that those kinds of QPaths are simple is probably not true if the Ty
// contains const arguments. Is there a *concise* way to check for this?
hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => Simple,
// FIXME: Can they contain const arguments and thus leak private struct fields?
hir::ExprKind::Path(hir::QPath::LangItem(..)) => Simple,
_ => Complex,
}
}

View File

@@ -10,7 +10,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in};
use rustc_hir::def::DefKind;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::lints::DelayedLint;
use rustc_hir::*;
@@ -203,6 +203,20 @@ impl<'tcx> TyCtxt<'tcx> {
}
})
}
pub fn qpath_is_lang_item(self, qpath: QPath<'_>, lang_item: LangItem) -> bool {
self.qpath_lang_item(qpath) == Some(lang_item)
}
/// This does not use typeck results since this is intended to be used with generated code.
pub fn qpath_lang_item(self, qpath: QPath<'_>) -> Option<LangItem> {
if let QPath::Resolved(_, path) = qpath
&& let Res::Def(_, def_id) = path.res
{
return self.lang_items().from_def_id(def_id);
}
None
}
}
/// Hashes computed by [`TyCtxt::hash_owner_nodes`] if necessary.

View File

@@ -266,7 +266,7 @@ impl<'tcx> TypeckResults<'tcx> {
pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: HirId) -> Res {
match *qpath {
hir::QPath::Resolved(_, path) => path.res,
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
hir::QPath::TypeRelative(..) => self
.type_dependent_def(id)
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
}

View File

@@ -425,7 +425,6 @@ impl<'tcx> ThirBuildCx<'tcx> {
None
}
}
_ => None,
}
} else {
None

View File

@@ -1268,7 +1268,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
Res::Def(kind, def_id) => Some((kind, def_id)),
_ => None,
},
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
hir::QPath::TypeRelative(..) => {
match self.maybe_typeck_results {
Some(typeck_results) => typeck_results.type_dependent_def(id),
// FIXME: Check type-relative associated types in signatures.
@@ -1287,9 +1287,6 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
if let DefKind::Static { .. } = kind { def_id.is_local() } else { false };
if !self.item_is_accessible(def_id) && !is_local_static {
let name = match *qpath {
hir::QPath::LangItem(it, ..) => {
self.tcx.lang_items().get(it).map(|did| self.tcx.def_path_str(did))
}
hir::QPath::Resolved(_, path) => Some(self.tcx.def_path_str(path.res.def_id())),
hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
};

View File

@@ -517,6 +517,7 @@ symbols! {
async_fn_track_caller,
async_fn_traits,
async_for_loop,
async_gen_internals,
async_iterator,
async_iterator_poll_next,
async_trait_bounds,

View File

@@ -1147,7 +1147,6 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
Box::new(segment.into_iter())
}
hir::QPath::LangItem(_, _) => Box::new(iter::empty()),
}
}
}