Skip to content

Add lints for discouraging eager / lazy function arguments#17108

Open
Naxdy wants to merge 2 commits into
rust-lang:masterfrom
Naxdy:feat/lazy-eager-calls
Open

Add lints for discouraging eager / lazy function arguments#17108
Naxdy wants to merge 2 commits into
rust-lang:masterfrom
Naxdy:feat/lazy-eager-calls

Conversation

@Naxdy

@Naxdy Naxdy commented May 28, 2026

Copy link
Copy Markdown

Closes #13678

Basically what or_fun_call and unnecessary_lazy_eval already do, except controlled by an attribute that can be added to any function by downstream library authors. Two major use cases that immediately come to mind are anyhow's .context vs. with_context, and eyre's .wrap_err vs. .wrap_err_with.

Refer to the docs in this PR for some more detailed explanation, but the basic gist is that library authors will be able to do something like this:

#[clippy::avoid_eager_arguments = "prefer using `lazy_foo` instead of eagerly evaluating `argument`"]
fn foo(argument: String) {
    // Perform some logic that only rarely involves the use of `argument`
}

#[clippy::optional_lazy_eval = "if `argument` does not require evaluation, prefer using `foo` instead"]
fn lazy_foo<F>(argument: F)
where
    F: FnOnce() -> String
{
    /// Perform some logic and evaluate `argument` on the fly, only if it is needed.
}

fn main() {
    let s = String::from("bar");

    // These two are fine
    foo(s);
    lazy_foo(|| String::from("bar"));

    let s = String::from("bar");

    // These will be linted against
    lazy_foo(move || s);
    foo(String::from("baz"));
}

Also a thought for the future: These lints could potentially replace or_fun_call and unnecessary_lazy_eval altogether if the corresponding attributes were added to the relevant methods in Option and Result. I've thought about simply amending the two, but didn't want to potentially break backwards compatibility.

Todo:

  • The docs need the actual Clippy version that introduces this lint. I intentionally left it blank for now, until we know if/when this can be included.

changelog: Adds new lints eager_fun_call and discouraged_lazy_evaluation that check for calling functions with eagerly evaluated arguments, and unnecessary closures used to produce arguments respectively.

@rustbot rustbot added the needs-fcp PRs that add, remove, or rename lints and need an FCP label May 28, 2026
@Naxdy Naxdy force-pushed the feat/lazy-eager-calls branch 8 times, most recently from 8c0bb35 to c58fafc Compare May 29, 2026 09:43
@rustbot

This comment has been minimized.

@Naxdy Naxdy force-pushed the feat/lazy-eager-calls branch from c58fafc to 3e35de4 Compare June 6, 2026 13:01
@Naxdy Naxdy force-pushed the feat/lazy-eager-calls branch from 3e35de4 to 7f7343b Compare June 6, 2026 13:39
@Naxdy Naxdy marked this pull request as ready for review June 6, 2026 14:16
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Jun 6, 2026
@rustbot

rustbot commented Jun 6, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @Jarcho (or someone else) some time within the next two weeks.

Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (S-waiting-on-review and S-waiting-on-author) stays updated, invoking these commands when appropriate:

  • @rustbot author: the review is finished, PR author should check the comments and take action accordingly
  • @rustbot review: the author is ready for a review, this PR will be queued again in the reviewer's queue
Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: 8 candidates
  • 8 candidates expanded to 8 candidates
  • Random selection from Jarcho, dswij, llogiq, samueltardieu

@Naxdy Naxdy changed the title WIP: Add lints for discouraging eager / lazy function arguments Add lints for discouraging eager / lazy function arguments Jun 6, 2026
@rustbot

rustbot commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

☔ The latest upstream changes (possibly #17164) made this pull request unmergeable. Please resolve the merge conflicts.

@Jarcho Jarcho left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be one lint pass. There's no reason to do almost the same initial work for every call twice.

View changes since this review

Comment on lines +56 to +67
fn check_fn(
&mut self,
cx: &LateContext<'tcx>,
_: FnKind<'_>,
_: &FnDecl<'_>,
body: &'tcx Body<'_>,
_: Span,
_: LocalDefId,
) {
let mut visitor = DiscouragedLazyEvaluationVisitor { cx };
walk_body(&mut visitor, body);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be check_expr.

Comment on lines +76 to +78
if let ExprKind::Call(func, args) = expr.kind
&& let ExprKind::Path(ref qpath) = func.kind
&& let Some(def_id) = self.cx.qpath_res(qpath, func.hir_id).opt_def_id()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't handle method calls. Calls to functions without arguments should also not be checked any further.

})
.collect();

if !lazy_args.is_empty() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why collect just to check if it's empty. This is what any is for.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Jun 7, 2026
@rustbot

rustbot commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@Jarcho

Jarcho commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

These attributes should name the alternative function in a way that allows us to find it. We can't correctly trigger the lint if we don't know which arguments to check, so at a minimum those need to be labelled as well. If we can lookup the alternative function then we can auto-detect which argument(s) is changing base on the types involved.

@Jarcho

Jarcho commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

@rustbot label lint-nominated

@rustbot rustbot added the lint-nominated Create an FCP-thread on Zulip for this PR label Jun 7, 2026
@rustbot

rustbot commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

This lint has been nominated for inclusion.

A FCP topic has been created on Zulip.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lint-nominated Create an FCP-thread on Zulip for this PR needs-fcp PRs that add, remove, or rename lints and need an FCP S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lint against patterns like <Result<_,_> as anyhow::Context>::context(r, &format!("...", ...)) in favor of .with_context(|| ...)

3 participants