From 5bd4ec0a21bfc0f1482f8824cd7f8a5a37a74334 Mon Sep 17 00:00:00 2001 From: ttozzi Date: Wed, 15 Oct 2025 03:07:46 +0900 Subject: [PATCH] Fix invalid rewrite in UseExplicitNilCheckInConditions by skipping when explicit optional type annotation is present --- Documentation/RuleDocumentation.md | 4 ++++ .../Rules/UseExplicitNilCheckInConditions.swift | 7 ++++++- .../UseExplicitNilCheckInConditionsTests.swift | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Documentation/RuleDocumentation.md b/Documentation/RuleDocumentation.md index 510cc0704..4a0f0bf1f 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 6e7e3e6c0..5c2f6bdae 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 d526df02b..28cca0205 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() {} + """ + ) + } }