Remove QPath::LangItem from try

This commit is contained in:
Cameron Steffen 2025-09-01 15:08:46 -05:00
parent bd13c30d98
commit a96e21b199
12 changed files with 49 additions and 89 deletions

View file

@ -609,7 +609,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
expr: &'hir hir::Expr<'hir>,
overall_span: Span,
) -> &'hir hir::Expr<'hir> {
let constructor = self.arena.alloc(self.expr_lang_item_qpath(method_span, lang_item));
let constructor = self.arena.alloc(self.expr_lang_item_path(method_span, lang_item));
self.expr_call(overall_span, constructor, std::slice::from_ref(expr))
}
@ -1950,7 +1950,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// expand <expr>
let sub_expr = self.lower_expr_mut(sub_expr);
self.expr_call_lang_item_qpath_fn(
self.expr_call_lang_item_fn(
unstable_span,
hir::LangItem::TryTraitBranch,
arena_vec![self; sub_expr],

View file

@ -545,9 +545,7 @@ 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(QPath::LangItem(..)) => unreachable!(),
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 +746,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>,
@ -780,6 +770,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
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 {

View file

@ -691,41 +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::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)]

View file

@ -1291,10 +1291,7 @@ 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))
}
QPath::LangItem(..) => unreachable!(),
}
}

View file

@ -5,7 +5,7 @@ use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::option_arg_ty;
use rustc_errors::Applicability;
use rustc_hir::LangItem::ResultErr;
use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath};
use rustc_hir::{Expr, ExprKind, LangItem, MatchSource};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
use rustc_span::{hygiene, sym};
@ -23,8 +23,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
// val,
// };
if let ExprKind::Call(match_fun, [try_arg]) = scrutinee.kind
&& let ExprKind::Path(ref match_fun_path) = match_fun.kind
&& matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..))
&& let ExprKind::Path(match_fun_path) = match_fun.kind
&& cx.tcx.qpath_is_lang_item(match_fun_path, LangItem::TryTraitBranch)
&& let ExprKind::Call(err_fun, [err_arg]) = try_arg.kind
&& err_fun.res(cx).ctor_parent(cx).is_lang_item(cx, ResultErr)
&& let Some(return_ty) = find_return_type(cx, &expr.kind)

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::is_copy;
use rustc_errors::Applicability;
use rustc_hir::{BindingMode, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
use rustc_hir::{BindingMode, ByRef, Expr, ExprKind, MatchSource, Node, PatKind};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_middle::ty::adjustment::Adjust;
@ -47,7 +47,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>)
// ? is a Call, makes sure not to rec *x?, but rather (*x)?
ExprKind::Call(hir_callee, [_]) => matches!(
hir_callee.kind,
ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, ..))
ExprKind::Path(qpath)
if cx.tcx.qpath_is_lang_item(qpath, rustc_hir::LangItem::TryTraitBranch)
),
ExprKind::MethodCall(_, self_arg, ..) if expr.hir_id == self_arg.hir_id => true,
ExprKind::Match(_, _, MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar)

View file

@ -9,7 +9,7 @@ use clippy_utils::{paths, sym};
use core::ops::ControlFlow;
use rustc_errors::Applicability;
use rustc_hir::{
BindingMode, Expr, ExprKind, HirId, LangItem, LetStmt, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind,
BindingMode, Expr, ExprKind, HirId, LangItem, LetStmt, MatchSource, Node, Pat, PatKind, Stmt, StmtKind,
};
use rustc_lint::LateContext;
use rustc_middle::ty;
@ -332,12 +332,12 @@ fn parse_iter_usage<'tcx>(
let (unwrap_kind, span) = if let Some((_, Node::Expr(e))) = iter.next() {
match e.kind {
ExprKind::Call(
Expr {
kind: ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)),
&Expr {
kind: ExprKind::Path(qpath),
..
},
[_],
) => {
) if cx.tcx.qpath_is_lang_item(qpath, LangItem::TryTraitBranch) => {
let parent_span = e.span.parent_callsite().unwrap();
if parent_span.ctxt() == ctxt {
(Some(UnwrapKind::QuestionMark), parent_span)

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::res::MaybeQPath;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Block, Body, Expr, ExprKind, LangItem, MatchSource, QPath};
use rustc_hir::{Block, Body, Expr, ExprKind, LangItem, MatchSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
@ -105,7 +105,8 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
}
&& let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar(_)) = &arg.kind
&& let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind
&& let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind
&& let ExprKind::Path(qpath) = called.kind
&& cx.tcx.qpath_is_lang_item(qpath, LangItem::TryTraitBranch)
&& expr.span.eq_ctxt(inner_expr.span)
&& let expr_ty = cx.typeck_results().expr_ty(expr)
&& let inner_ty = cx.typeck_results().expr_ty(inner_expr)

View file

@ -530,11 +530,13 @@ impl QuestionMark {
}
}
fn is_try_block(bl: &Block<'_>) -> bool {
fn is_try_block(cx: &LateContext<'_>, bl: &Block<'_>) -> bool {
if let Some(expr) = bl.expr
&& let ExprKind::Call(callee, [_]) = expr.kind
&& let ExprKind::Path(qpath) = callee.kind
&& cx.tcx.qpath_is_lang_item(qpath, LangItem::TryTraitFromOutput)
{
callee.opt_lang_path() == Some(LangItem::TryTraitFromOutput)
true
} else {
false
}
@ -590,8 +592,8 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark {
}
}
fn check_block(&mut self, _: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
if is_try_block(block) {
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
if is_try_block(cx, block) {
*self
.try_block_depth_stack
.last_mut()
@ -607,8 +609,8 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark {
self.try_block_depth_stack.pop();
}
fn check_block_post(&mut self, _: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
if is_try_block(block) {
fn check_block_post(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
if is_try_block(cx, block) {
*self
.try_block_depth_stack
.last_mut()

View file

@ -7,7 +7,7 @@ use clippy_utils::{
use rustc_ast::MetaItemInner;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, Expr, ExprKind, HirId, LangItem, MatchSource, QPath, StmtKind};
use rustc_hir::{Body, Expr, ExprKind, HirId, LangItem, MatchSource, StmtKind};
use rustc_lint::{LateContext, Level, LintContext};
use rustc_middle::ty::{self, Ty};
use rustc_span::{BytePos, Pos, Span};
@ -134,7 +134,8 @@ fn check_final_expr<'tcx>(
let replacement = if let Some(inner_expr) = inner {
// if desugar of `do yeet`, don't lint
if let ExprKind::Call(path_expr, [_]) = inner_expr.kind
&& let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, ..)) = path_expr.kind
&& let ExprKind::Path(qpath) = path_expr.kind
&& cx.tcx.qpath_is_lang_item(qpath, LangItem::TryTraitFromYeet)
{
return;
}

View file

@ -192,7 +192,7 @@ fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) {
fn should_lint<'a>(cx: &LateContext<'a>, mut inner: &'a hir::Expr<'a>) -> Option<IoOp> {
inner = unpack_match(inner);
inner = unpack_try(inner);
inner = unpack_try(cx, inner);
inner = unpack_call_chain(inner);
inner = unpack_await(cx, inner);
// we type-check it to get whether it's a read/write or their vectorized forms
@ -256,12 +256,10 @@ fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
expr
}
fn unpack_try<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
fn unpack_try<'a>(cx: &LateContext<'_>, mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
while let ExprKind::Call(func, [arg_0]) = expr.kind
&& matches!(
func.kind,
ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..))
)
&& let ExprKind::Path(qpath) = func.kind
&& cx.tcx.qpath_is_lang_item(qpath, hir::LangItem::TryTraitBranch)
{
expr = arg_0;
}

View file

@ -253,10 +253,7 @@ mod expressions {
}
/// ExprKind::TryBlock
fn expr_try_block() {
{ #[lang = "from_output"](()) }
{ return; #[lang = "from_output"](()) }
}
fn expr_try_block() { { from_output(()) } { return; from_output(()) } }
/// ExprKind::Assign
fn expr_assign() { let expr; expr = true; }
@ -373,20 +370,17 @@ mod expressions {
/// ExprKind::Try
fn expr_try() {
let expr;
match #[lang = "branch"](expr) {
#[lang = "Break"] { 0: residual } => #[allow(unreachable_code)]
return #[lang = "from_residual"](residual),
#[lang = "Continue"] { 0: val } => #[allow(unreachable_code)]
match branch(expr) {
Break { 0: residual } => #[allow(unreachable_code)]
return from_residual(residual),
Continue { 0: val } => #[allow(unreachable_code)]
val,
};
}
/// ExprKind::Yield
fn expr_yield() { yield (); yield true; }
/// ExprKind::Yeet
fn expr_yeet() {
return #[lang = "from_yeet"](());
return #[lang = "from_yeet"](0);
}
fn expr_yeet() { return from_yeet(()); return from_yeet(0); }
/// ExprKind::Become
fn expr_become() { become true; }
/// ExprKind::IncludedBytes