Skip to content

Rust 2024 Let-Chain Candidate

Description

Rust 2024 supports let conditions in boolean chains, so an if let wrapping a single nested if can often be collapsed into one condition.

This rule reports the outer if only when neither branch has an else, the outer block contains a single inner if statement, and either the outer or inner condition is an if let.

YAML

yaml
id: rust-2024-let-chain-candidate
language: Rust
severity: hint
message: nested if conditions can be collapsed into a Rust 2024 let-chain

utils:
  # The nested if statement should be the only statement in its block.
  sole-child:
    all:
      - nthChild: 1
      - nthChild:
          position: 1
          reverse: true

  # Let-chains can only preserve behavior when there is no else branch.
  if-no-else:
    kind: if_expression
    not:
      has:
        field: alternative
        kind: else_clause

  # At least one side of the nested if pair must be an if let.
  if-let-no-else:
    matches: if-no-else
    has:
      field: condition
      kind: let_condition

  # Match an inner if that is the sole statement inside the outer if block.
  sole-inner-if-stmt:
    kind: expression_statement
    matches: sole-child
    has:
      matches: if-no-else

  # Same as above, but require the inner if to be an if let.
  sole-inner-if-let-stmt:
    kind: expression_statement
    matches: sole-child
    has:
      matches: if-let-no-else

rule:
  # Start from an outer if without an else branch.
  matches: if-no-else
  # Its direct consequence block must contain exactly one inner if statement.
  has:
    field: consequence
    kind: block
    has:
      matches: sole-inner-if-stmt
  # Either the outer condition or the inner condition must bind with if let.
  any:
    - matches: if-let-no-else
    - has:
        field: consequence
        kind: block
        has:
          matches: sole-inner-if-let-stmt

Example

rs
fn handle_request(user: Option<User>, cfg: Config) {
    if let Some(user) = user {
        if user.is_active() {
            grant_access(user);
        }
    }

    if cfg!(debug_assertions) {
        if let Some(path) = cfg.log_path() {
            enable_file_logging(path);
        }
    }

    // OK: the inner if is not the only statement in the block.
    if let Some(user) = current_user() {
        audit(&user);
        if user.is_admin() {
            grant_admin(user);
        }
    }

    // OK: this has an else branch.
    if let Some(path) = cfg.cache_path() {
        if path.exists() {
            load_cache(path);
        }
    } else {
        rebuild_cache();
    }
}

Contributed by

Codex (GPT-5.5 high fast)

Made with ❤️ with Rust