fix: result_large_err FN on closures

This commit is contained in:
Linshu Yang 2025-12-20 22:03:16 +00:00
parent 34fab5cd37
commit 3cf9fa5496
4 changed files with 68 additions and 6 deletions

View file

@ -596,4 +596,8 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api);
ref_option::check_trait_item(cx, item, self.avoid_breaking_exported_api);
}
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
result::check_expr(cx, expr, self.large_error_threshold, &self.large_error_ignored);
}
}

View file

@ -50,7 +50,7 @@ pub(super) fn check_item<'tcx>(
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
check_result_unit_err(cx, err_ty, fn_header_span, msrv);
}
check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored);
check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored, false);
}
}
@ -70,7 +70,7 @@ pub(super) fn check_impl_item<'tcx>(
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
check_result_unit_err(cx, err_ty, fn_header_span, msrv);
}
check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored);
check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored, false);
}
}
@ -87,7 +87,7 @@ pub(super) fn check_trait_item<'tcx>(
if cx.effective_visibilities.is_exported(item.owner_id.def_id) {
check_result_unit_err(cx, err_ty, fn_header_span, msrv);
}
check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored);
check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored, false);
}
}
}
@ -111,12 +111,15 @@ fn check_result_large_err<'tcx>(
hir_ty_span: Span,
large_err_threshold: u64,
large_err_ignored: &DefIdSet,
is_closure: bool,
) {
if let ty::Adt(adt, _) = err_ty.kind()
&& large_err_ignored.contains(&adt.did())
{
return;
}
let subject = if is_closure { "closure" } else { "function" };
if let ty::Adt(adt, subst) = err_ty.kind()
&& let Some(local_def_id) = adt.did().as_local()
&& let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_def_id)
@ -130,7 +133,7 @@ fn check_result_large_err<'tcx>(
cx,
RESULT_LARGE_ERR,
hir_ty_span,
"the `Err`-variant returned from this function is very large",
format!("the `Err`-variant returned from this {subject} is very large"),
|diag| {
diag.span_label(
def.variants[first_variant.ind].span,
@ -161,7 +164,7 @@ fn check_result_large_err<'tcx>(
cx,
RESULT_LARGE_ERR,
hir_ty_span,
"the `Err`-variant returned from this function is very large",
format!("the `Err`-variant returned from this {subject} is very large"),
|diag: &mut Diag<'_, ()>| {
diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes"));
diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
@ -170,3 +173,33 @@ fn check_result_large_err<'tcx>(
}
}
}
pub(super) fn check_expr<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
large_err_threshold: u64,
large_err_ignored: &DefIdSet,
) {
if let hir::ExprKind::Closure(closure) = expr.kind
&& let ty::Closure(_, args) = cx.typeck_results().expr_ty(expr).kind()
&& let closure_sig = args.as_closure().sig()
&& let Ok(err_binder) = closure_sig.output().try_map_bound(|output_ty| {
if let ty::Adt(adt, args) = output_ty.kind()
&& let [_, err_arg] = args.as_slice()
&& let Some(err_ty) = err_arg.as_type()
&& adt.is_diag_item(cx, sym::Result)
{
return Ok(err_ty);
}
Err(())
})
{
let err_ty = cx.tcx.instantiate_bound_regions_with_erased(err_binder);
let hir_ty_span = match closure.fn_decl.output {
hir::FnRetTy::Return(hir_ty) => hir_ty.span,
hir::FnRetTy::DefaultReturn(_) => expr.span,
};
check_result_large_err(cx, err_ty, hir_ty_span, large_err_threshold, large_err_ignored, true);
}
}

View file

@ -141,3 +141,12 @@ fn _empty_error() -> Result<(), Empty> {
}
fn main() {}
fn issue16249() {
type Large = [u8; 1024];
let closure = || -> Result<(), Large> { Ok(()) };
//~^ result_large_err
let closure = || Ok::<(), Large>(());
//~^ result_large_err
}

View file

@ -104,5 +104,21 @@ LL | pub fn array_error<T, U>() -> Result<(), ArrayError<(i32, T), U>> {
|
= help: try reducing the size of `ArrayError<(i32, T), U>`, for example by boxing large elements or replacing it with `Box<ArrayError<(i32, T), U>>`
error: aborting due to 12 previous errors
error: the `Err`-variant returned from this closure is very large
--> tests/ui/result_large_err.rs:148:25
|
LL | let closure = || -> Result<(), Large> { Ok(()) };
| ^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 1024 bytes
|
= help: try reducing the size of `[u8; 1024]`, for example by boxing large elements or replacing it with `Box<[u8; 1024]>`
error: the `Err`-variant returned from this closure is very large
--> tests/ui/result_large_err.rs:150:19
|
LL | let closure = || Ok::<(), Large>(());
| ^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 1024 bytes
|
= help: try reducing the size of `[u8; 1024]`, for example by boxing large elements or replacing it with `Box<[u8; 1024]>`
error: aborting due to 14 previous errors