ArgParser: reject default attributes on non-Choice fields at generation time - #572
Merged
Conversation
…on time `[<ArgumentDefaultFunction>]` and `[<ArgumentDefaultEnvironmentVariable>]` were only ever read inside the Choice-parsing path, so on any non-Choice field the generator accepted them and silently dropped the default, leaving the field required (issue #571). Defaults are intentionally surfaced through `Choice<'a, 'a>` so a successful parse can report whether a value was user-supplied (Choice1Of2) or defaulted (Choice2Of2); a bare field cannot express this, so honouring the default would be impossible and dropping it silently is a fail-fast gap. Add a syntactic guard in `toParseSpec` that rejects a default attribute on any field whose type is not `Choice<'a, 'a>`, and on any positional field, with messages pointing at the Choice convention. The now-unreachable positional default-rejection arm inside the positional `getChoice` callback is removed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #571.
Problem
[<ArgumentDefaultFunction>]and[<ArgumentDefaultEnvironmentVariable>]are only ever read inside theChoiceTypebranch ofcreateParseFunction. On any non-Choicefield the generator accepted them, generated code without complaint, and silently dropped the default — the field stayed required at parse time. This is a fail-fast gap: an attribute that cannot be honoured should be rejected at generation time.Defaults are intentionally surfaced through
Choice<'a, 'a>so a successful parse can distinguish a user-supplied value (Choice1Of2) from a parser-filled default (Choice2Of2). A bare field cannot express "was this defaulted?", so honouring the default is impossible — but the generator didn't say so.Fix
A syntactic guard in
toParseSpec's per-field fold, before the record/union/positional dispatch. If a field carries a default attribute:Choice<_,_>→ accepted, unchanged (an unequalChoice<int,string>still hits the pre-existing "prove types equal" error);Choice<'a,'a>convention.The now-unreachable positional default-rejection arm inside the positional
getChoicecallback is removed (the guard front-runs it).Tests
Five new tests in
TestArgParserRejection.fs, written first and observed failing before the guard:ArgumentDefaultFunction);ArgumentDefaultEnvironmentVariable);Choice<int,int>field with a default still generates.Verification
ConsumePluginbuilds clean — every realChoice-typed default field still generates.🤖 Generated with Claude Code