Skip to content

Commit 96f7204

Browse files
Smaug123claude
andcommitted
See through parentheses when resolving ambient type references
FCS represents `of (FooArgs)` as SynType.Paren, so the by-name lookups for a union case's payload record and for union- or record-typed fields rejected declarations which were valid without the parentheses. Strip optional parens before all three lookups. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 550182c commit 96f7204

2 files changed

Lines changed: 82 additions & 3 deletions

File tree

WoofWare.Myriad.Plugins/ArgParserGenerator.fs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -895,14 +895,14 @@ module internal ArgParserGenerator =
895895
| l -> List.ofSeq l
896896

897897
let ambientRecordMatch =
898-
match fieldType with
898+
match SynType.stripOptionalParen fieldType with
899899
| SynType.LongIdent (SynLongIdent.SynLongIdent (id, _, _)) ->
900900
let target = List.last(id).idText
901901
ambientRecords |> List.tryFind (fun r -> r.Name.idText = target)
902902
| _ -> None
903903

904904
let ambientUnionMatch =
905-
match fieldType with
905+
match SynType.stripOptionalParen fieldType with
906906
| SynType.LongIdent (SynLongIdent.SynLongIdent (id, _, _)) ->
907907
let target = List.last(id).idText
908908
ambientUnions |> List.tryFind (fun u -> u.Name.idText = target)
@@ -1068,7 +1068,7 @@ module internal ArgParserGenerator =
10681068
match case.Fields with
10691069
| [ field ] ->
10701070
let payload =
1071-
match field.Type with
1071+
match SynType.stripOptionalParen field.Type with
10721072
| SynType.LongIdent (SynLongIdent.SynLongIdent (id, _, _)) ->
10731073
let target = List.last(id).idText
10741074
ambientRecords |> List.tryFind (fun r -> r.Name.idText = target)

WoofWare.Myriad.Plugins/Test/TestArgParserRejection.fs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,85 @@ type BadDu =
541541
|> shouldRejectWith
542542
"Case FooCase of [<ArgParser>] union BadDu must have exactly one field: a record holding that case's arguments."
543543

544+
[<Test>]
545+
let ``Parenthesized type references are accepted wherever bare ones are`` () =
546+
// FCS represents `of (FooArgs)` as SynType.Paren; the by-name lookups for a case's
547+
// payload record, and for union- or record-typed fields, must see through it.
548+
let modules =
549+
generateFromSource
550+
"""namespace TestMe
551+
552+
open WoofWare.Myriad.Plugins
553+
554+
type FooArgs =
555+
{
556+
Foo : int
557+
}
558+
559+
type BarArgs =
560+
{
561+
Bar : int
562+
}
563+
564+
[<ArgParser>]
565+
type DuArgs =
566+
| FooCase of (FooArgs)
567+
| BarCase of BarArgs
568+
"""
569+
570+
List.length modules |> shouldEqual 2
571+
572+
let modules =
573+
generateFromSource
574+
"""namespace TestMe
575+
576+
open WoofWare.Myriad.Plugins
577+
578+
type AutoMode =
579+
{
580+
Quiet : bool option
581+
}
582+
583+
type ManualMode =
584+
{
585+
Level : int
586+
}
587+
588+
type Mode =
589+
| Auto of AutoMode
590+
| Manual of ManualMode
591+
592+
[<ArgParser>]
593+
type WithModeArgs =
594+
{
595+
Verbose : bool
596+
Mode : (Mode)
597+
}
598+
"""
599+
600+
List.length modules |> shouldEqual 2
601+
602+
let modules =
603+
generateFromSource
604+
"""namespace TestMe
605+
606+
open WoofWare.Myriad.Plugins
607+
608+
type ChildRecord =
609+
{
610+
Thing : int
611+
}
612+
613+
[<ArgParser>]
614+
type ParentRecord =
615+
{
616+
Child : (ChildRecord)
617+
AndAnother : bool
618+
}
619+
"""
620+
621+
List.length modules |> shouldEqual 2
622+
544623
[<Test>]
545624
let ``The motivating union of alternative argument sets generates successfully`` () =
546625
let modules =

0 commit comments

Comments
 (0)