Skip to content

Improve diagnostic for @Flag Bool? without inversion:#892

Merged
rauhul merged 2 commits into
apple:mainfrom
qflen:improve-bool-optional-flag-diagnostic
Apr 23, 2026
Merged

Improve diagnostic for @Flag Bool? without inversion:#892
rauhul merged 2 commits into
apple:mainfrom
qflen:improve-bool-optional-flag-diagnostic

Conversation

@qflen
Copy link
Copy Markdown
Contributor

@qflen qflen commented Apr 21, 2026

Resolves #835.

Problem

When a user writes the following, which looks reasonable:

@Flag(help: "Write empty files.")
var writeEmptyFiles: Bool?

the compiler produces a confusing diagnostic:

error: referencing initializer 'init(name:help:)' on 'Flag' requires the types 'Bool?' and 'Int' be equivalent

The actual cause is that every Flag where Value == Bool? init requires an inversion: parameter. Without one, overload resolution falls through to the Flag where Value == Int counter initializer at Flag.swift:385, which is the first init(name:help:) the compiler can see, and the Bool? vs Int mismatch surfaces from there.

Fix

Add an @available(*, unavailable) init overload on Flag where Value == Bool? whose signature matches the offending call shape. Overload resolution now picks this one because its where clause is more specific, and the custom message: points the user at the real cause:

error: 'init(name:help:)' is unavailable: An optional 'Bool?' @Flag requires an 'inversion:' parameter, such as '.prefixedNo' or '.prefixedEnableDisable'.

This follows the same pattern used for the existing unavailable no-arg Flag.init() at Flag.swift:94-101, whose doc comment already explains this technique:

Explicitly marking this initializer unavailable means that when Value is a type supported by Flag like Bool or EnumerableFlag, the appropriate overload will be selected instead.

Test plan

  • swift test passes (495 tests, no failures)
  • Reproduced the original confusing error on main
  • Verified the new diagnostic message appears for @Flag(help: "...") var x: Bool?
  • Verified the legitimate usage @Flag(inversion: .prefixedEnableDisable) var x: Bool? still compiles and runs correctly

Copy link
Copy Markdown
Collaborator

@rauhul rauhul left a comment

Choose a reason for hiding this comment

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

I want @natecook1000's eyes on this as it affects the public api, albeit with an unusable symbol

When a user declares `@Flag(...) var x: Bool?` without the required
`inversion:` parameter, overload resolution falls through to the
`Flag where Value == Int` initializer and the compiler reports
"requires the types 'Bool?' and 'Int' be equivalent", which does not
point the user at the real cause.

Add an `@available(*, unavailable)` init overload on
`Flag where Value == Bool?` with a message that names the missing
parameter. Follows the same pattern used for the unavailable no-arg
`Flag.init()` at the top of the file.

Resolves apple#835.
@qflen qflen force-pushed the improve-bool-optional-flag-diagnostic branch from f27a3d1 to 796f502 Compare April 21, 2026 19:40
Copy link
Copy Markdown
Member

@natecook1000 natecook1000 left a comment

Choose a reason for hiding this comment

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

Thanks, @qflen! LGTM with one minor change.

Comment thread Sources/ArgumentParser/Parsable Properties/Flag.swift Outdated
Co-authored-by: Nate Cook <natecook@apple.com>
@rauhul rauhul merged commit a544331 into apple:main Apr 23, 2026
34 of 35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unhelpful compiler error for @Flag var _: Bool? without a default value

3 participants