diff --git a/Documentation/RuleDocumentation.md b/Documentation/RuleDocumentation.md index 510cc070..4a0f0bf1 100644 --- a/Documentation/RuleDocumentation.md +++ b/Documentation/RuleDocumentation.md @@ -490,6 +490,10 @@ than binding and immediately discarding the value. For example, `if let _ = someValue { ... }` is forbidden. Use `if someValue != nil { ... }` instead. +Note: If the conditional binding carries an explicit type annotation (e.g. `if let _: S? = expr`), +we skip the transformation. Such annotations can be necessary to drive generic type inference +when a function mentions a type only in its return position. + Lint: `let _ = expr` inside a condition list will yield a lint error. Format: `let _ = expr` inside a condition list will be replaced by `expr != nil`. diff --git a/Sources/SwiftFormat/Rules/UseExplicitNilCheckInConditions.swift b/Sources/SwiftFormat/Rules/UseExplicitNilCheckInConditions.swift index 6e7e3e6c..5c2f6bda 100644 --- a/Sources/SwiftFormat/Rules/UseExplicitNilCheckInConditions.swift +++ b/Sources/SwiftFormat/Rules/UseExplicitNilCheckInConditions.swift @@ -19,6 +19,10 @@ import SwiftSyntaxBuilder /// For example, `if let _ = someValue { ... }` is forbidden. Use `if someValue != nil { ... }` /// instead. /// +/// Note: If the conditional binding carries an explicit type annotation (e.g. `if let _: S? = expr`), +/// we skip the transformation. Such annotations can be necessary to drive generic type inference +/// when a function mentions a type only in its return position. +/// /// Lint: `let _ = expr` inside a condition list will yield a lint error. /// /// Format: `let _ = expr` inside a condition list will be replaced by `expr != nil`. @@ -29,7 +33,8 @@ public final class UseExplicitNilCheckInConditions: SyntaxFormatRule { case .optionalBinding(let optionalBindingCondition): guard let initializerClause = optionalBindingCondition.initializer, - isDiscardedAssignmentPattern(optionalBindingCondition.pattern) + isDiscardedAssignmentPattern(optionalBindingCondition.pattern), + optionalBindingCondition.typeAnnotation == nil else { return node } diff --git a/Tests/SwiftFormatTests/Rules/UseExplicitNilCheckInConditionsTests.swift b/Tests/SwiftFormatTests/Rules/UseExplicitNilCheckInConditionsTests.swift index d526df02..28cca020 100644 --- a/Tests/SwiftFormatTests/Rules/UseExplicitNilCheckInConditionsTests.swift +++ b/Tests/SwiftFormatTests/Rules/UseExplicitNilCheckInConditionsTests.swift @@ -160,4 +160,18 @@ final class UseExplicitNilCheckInConditionsTests: LintOrFormatRuleTestCase { ] ) } + + func testTypeAnnotations() { + assertFormatting( + UseExplicitNilCheckInConditions.self, + input: """ + if let _: F = foo() {} + if let _: S? = foo() {} + """, + expected: """ + if let _: F = foo() {} + if let _: S? = foo() {} + """ + ) + } }