Skip to content

wrapConditionalBodies incorrectly wraps Swift 5.9+ if expressions #2545

Description

@KYHyeon

Summary

The wrapConditionalBodies rule's help text describes its scope as "inline conditional statements", but it currently also wraps Swift 5.9+ if expressions, which is unintended behavior.

Reproduction

// Input
.contains { if case .cancelled = $0 { true } else { false } }
let isX = if condition { true } else { false }

// Output (current — undesired)
.contains { if case .cancelled = $0 {
    true
} else {
    false
} }
let isX = if condition {
    true
} else {
    false
}

Verified with SwiftFormat 0.60.1:

swiftformat --rules wrapConditionalBodies --swift-version 6.0 <file>

Background

The rule was introduced in #989 (August 2021), before Swift 5.9 introduced if expressions (September 2023). This case was likely never considered.

SwiftLint's equivalent rule conditional_returns_on_newline naturally avoids this — it only triggers when the body contains a return statement, so if expressions are unaffected by design.

Suggested Fix

Skip wrapping when the if is used as an expression. Two cases to detect:

Case 1 — assignment context (let x = if ...):
Already detectable via the existing isConditionalAssignment(at:) helper.

Case 2 — closure/function body expression (.contains { if ... { true } else { false } }):
Harder to detect without type information. One possible heuristic is checking that all branches are exhaustive (else branch present) and no branch body starts with return, but this has edge cases. Open to suggestions on the right approach here.

Happy to submit a PR if this direction looks good.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions