Skip to content

Commit cfd4121

Browse files
authored
Parser: capture named fields block separators (#18857)
1 parent f1ca26a commit cfd4121

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+612
-211
lines changed

docs/release-notes/.FSharp.Compiler.Service/10.0.100.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
### Changed
2828
* Use `errorR` instead of `error` in `CheckDeclarations.fs` when possible. ([PR #18645](https://github.com/dotnet/fsharp/pull/18645))
29+
* Parser: Capture named fields block separators. ([PR #18857](https://github.com/dotnet/fsharp/pull/18857))
2930
* Type checker: use inner expr range in upcast constraints errors ([PR #18850](https://github.com/dotnet/fsharp/pull/18850))
3031

3132
### Breaking Changes

src/Compiler/Checking/CheckPatterns.fs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,13 @@ and TcPatArrayOrList warnOnUpper cenv env vFlags patEnv ty isArray args m =
457457
phase2, acc
458458

459459
and TcRecordPat warnOnUpper (cenv: cenv) env vFlags patEnv ty fieldPats m =
460-
let fieldPats = fieldPats |> List.map (fun (fieldId, _, fieldPat) -> fieldId, fieldPat)
460+
let fieldPats =
461+
fieldPats
462+
|> List.map (fun (NamePatPairField(fieldName = fieldLid; pat = pat)) ->
463+
match fieldLid.LongIdent with
464+
| [id] -> ([], id), pat
465+
| lid -> List.frontAndBack lid, pat)
466+
461467
match BuildFieldMap cenv env false ty fieldPats m with
462468
| None -> (fun _ -> TPat_error m), patEnv
463469
| Some(tinst, tcref, fldsmap, _fldsList) ->
@@ -503,7 +509,9 @@ and CheckNoArgsForLiteral args m =
503509
and GetSynArgPatterns args =
504510
match args with
505511
| SynArgPats.Pats args -> args
506-
| SynArgPats.NamePatPairs (pats = pairs) -> List.map (fun (_, _, pat) -> pat) pairs
512+
| SynArgPats.NamePatPairs (pats = pairs) ->
513+
pairs
514+
|> List.map _.Pattern
507515

508516
and TcArgPats warnOnUpper (cenv: cenv) env vFlags patEnv args =
509517
let g = cenv.g
@@ -657,7 +665,11 @@ and TcPatLongIdentUnionCaseOrExnCase warnOnUpper cenv env ad vFlags patEnv ty (m
657665
let result = Array.zeroCreate numArgTys
658666
let extraPatterns = List ()
659667

660-
for id, _, pat in pairs do
668+
for NamePatPairField(fieldName = fieldLid; pat = pat) in pairs do
669+
let id =
670+
match fieldLid.LongIdent with
671+
| [id] -> id
672+
| lid -> snd (List.frontAndBack lid)
661673
match argNames |> List.tryFindIndex (fun id2 -> id.idText = id2.Id.idText) with
662674
| None ->
663675
extraPatterns.Add pat

src/Compiler/Driver/GraphChecking/FileContentMapping.fs

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -622,20 +622,9 @@ let visitPat (p: SynPat) : FileContentEntry list =
622622
let continuations = List.map visit elementPats
623623
Continuation.concatenate continuations continuation
624624
| SynPat.Record(fieldPats, _) ->
625-
let pats = List.map (fun (_, _, p) -> p) fieldPats
626-
627-
let lids =
628-
[
629-
for (l, _), _, _ in fieldPats do
630-
yield! visitLongIdent l
631-
]
632-
625+
let pats = fieldPats |> List.map (fun f -> f.Pattern)
633626
let continuations = List.map visit pats
634-
635-
let finalContinuation nodes =
636-
[ yield! List.concat nodes; yield! lids ] |> continuation
637-
638-
Continuation.sequence continuations finalContinuation
627+
Continuation.concatenate continuations continuation
639628
| SynPat.Null _ -> continuation []
640629
| SynPat.OptionalVal _ -> continuation []
641630
| SynPat.IsInst(t, _) -> continuation (visitSynType t)
@@ -650,8 +639,8 @@ let visitSynArgPats (argPat: SynArgPats) =
650639
| SynArgPats.Pats args -> List.collect visitPat args
651640
| SynArgPats.NamePatPairs(pats = pats) ->
652641
[
653-
for _, _, p in pats do
654-
yield! visitPat p
642+
for p in pats do
643+
yield! visitPat p.Pattern
655644
]
656645

657646
let visitSynSimplePat (pat: SynSimplePat) =

src/Compiler/Service/ServiceParseTreeWalk.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -772,15 +772,15 @@ module SyntaxTraversal =
772772
| SynPat.Ands(ps, _)
773773
| SynPat.Tuple(elementPats = ps)
774774
| SynPat.ArrayOrList(_, ps, _) -> ps |> List.tryPick (traversePat path)
775-
| SynPat.Record(fieldPats = fieldPats) -> fieldPats |> List.tryPick (fun (_, _, p) -> traversePat path p)
775+
| SynPat.Record(fieldPats = fieldPats) -> fieldPats |> List.tryPick (fun x -> traversePat path x.Pattern)
776776
| SynPat.Attrib(p, attributes, m) ->
777777
match traversePat path p with
778778
| None -> attributeApplicationDives path attributes |> pick m attributes
779779
| x -> x
780780
| SynPat.LongIdent(argPats = args) ->
781781
match args with
782782
| SynArgPats.Pats ps -> ps |> List.tryPick (traversePat path)
783-
| SynArgPats.NamePatPairs(pats = ps) -> ps |> List.map (fun (_, _, pat) -> pat) |> List.tryPick (traversePat path)
783+
| SynArgPats.NamePatPairs(pats = ps) -> ps |> List.tryPick (fun x -> traversePat path x.Pattern)
784784
| SynPat.Typed(p, ty, _) ->
785785
match traversePat path p with
786786
| None -> traverseSynType path ty

src/Compiler/Service/ServiceParsedInputOps.fs

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ module ParsedInput =
613613
let (|ConstructorPats|) pats =
614614
match pats with
615615
| SynArgPats.Pats ps -> ps
616-
| SynArgPats.NamePatPairs(pats = xs) -> List.map (fun (_, _, pat) -> pat) xs
616+
| SynArgPats.NamePatPairs(pats = xs) -> xs |> List.map _.Pattern
617617

618618
let inline isPosInRange range = rangeContainsPos range pos
619619

@@ -1120,6 +1120,8 @@ module ParsedInput =
11201120
let last = List.last lid.LongIdent
11211121
last.idRange.End
11221122

1123+
let lastIdentOfSynLongIdent (lid: SynLongIdent) = List.last lid.LongIdent
1124+
11231125
let endOfClosingTokenOrLastIdent (mClosing: range option) (lid: SynLongIdent) =
11241126
match mClosing with
11251127
| Some m -> m.End
@@ -1293,18 +1295,24 @@ module ParsedInput =
12931295
rangeContainsPos m pos
12941296
->
12951297
pats
1296-
|> List.tryPick (fun (fieldId, _, pat) ->
1297-
if rangeContainsPos fieldId.idRange pos then
1298-
let referencedFields = pats |> List.map (fun (id, _, _) -> id.idText)
1298+
|> List.tryPick (fun field ->
1299+
if rangeContainsPos field.FieldName.Range pos then
1300+
let referencedFields =
1301+
pats |> List.map (fun f -> (lastIdentOfSynLongIdent f.FieldName).idText)
1302+
12991303
Some(CompletionContext.Pattern(PatternContext.UnionCaseFieldIdentifier(referencedFields, caseId.Range)))
13001304
else
1301-
let context = Some(PatternContext.NamedUnionCaseField(fieldId.idText, caseId.Range))
1302-
TryGetCompletionContextInPattern suppressIdentifierCompletions pat context pos)
1305+
let lastId = lastIdentOfSynLongIdent field.FieldName
1306+
let context = Some(PatternContext.NamedUnionCaseField(lastId.idText, caseId.Range))
1307+
1308+
TryGetCompletionContextInPattern suppressIdentifierCompletions field.Pattern context pos)
13031309
|> Option.orElseWith (fun () ->
13041310
// Last resort - check for fun (Case (item1 = a; | )) ->
13051311
// That is, pos is after the last pair and still within parentheses
13061312
if rangeBeforePos mPairs pos then
1307-
let referencedFields = pats |> List.map (fun (id, _, _) -> id.idText)
1313+
let referencedFields =
1314+
pats |> List.map (fun f -> (lastIdentOfSynLongIdent f.FieldName).idText)
1315+
13081316
Some(CompletionContext.Pattern(PatternContext.UnionCaseFieldIdentifier(referencedFields, caseId.Range)))
13091317
else
13101318
None)
@@ -1335,9 +1343,17 @@ module ParsedInput =
13351343
|> List.tryPick (fun pat -> TryGetCompletionContextInPattern false pat None pos)
13361344
| SynPat.Record(fieldPats = pats; range = m) when rangeContainsPos m pos ->
13371345
pats
1338-
|> List.tryPick (fun ((_, fieldId), _, pat) ->
1339-
if rangeContainsPos fieldId.idRange pos then
1340-
let referencedFields = pats |> List.map (fun ((_, x), _, _) -> x.idText, x.idRange)
1346+
|> List.tryPick (fun f ->
1347+
let fieldId = f.FieldName
1348+
let pat = f.Pattern
1349+
1350+
if rangeContainsPos fieldId.Range pos then
1351+
let referencedFields =
1352+
pats
1353+
|> List.map (fun f ->
1354+
let lastId = lastIdentOfSynLongIdent f.FieldName
1355+
lastId.idText, lastId.idRange)
1356+
13411357
Some(CompletionContext.Pattern(PatternContext.RecordFieldIdentifier referencedFields))
13421358
elif rangeContainsPos pat.Range pos then
13431359
TryGetCompletionContextInPattern false pat None pos
@@ -1348,13 +1364,22 @@ module ParsedInput =
13481364
// That is, pos is after the last field and still within braces
13491365
if
13501366
pats
1351-
|> List.forall (fun (_, mEquals, pat) ->
1352-
match mEquals, pat with
1367+
|> List.forall (fun f ->
1368+
let mEqualsOpt =
1369+
match f with
1370+
| NamePatPairField(equalsRange = m) -> m
1371+
1372+
match mEqualsOpt, f.Pattern with
13531373
| Some mEquals, SynPat.Wild mPat -> rangeBeforePos mEquals pos && mPat.StartColumn <> mPat.EndColumn
13541374
| Some mEquals, _ -> rangeBeforePos mEquals pos
13551375
| _ -> false)
13561376
then
1357-
let referencedFields = pats |> List.map (fun ((_, x), _, _) -> x.idText, x.idRange)
1377+
let referencedFields =
1378+
pats
1379+
|> List.map (fun f ->
1380+
let lastId = lastIdentOfSynLongIdent f.FieldName
1381+
lastId.idText, lastId.idRange)
1382+
13581383
Some(CompletionContext.Pattern(PatternContext.RecordFieldIdentifier referencedFields))
13591384
else
13601385
Some(CompletionContext.Pattern PatternContext.Other))
@@ -1870,7 +1895,7 @@ module ParsedInput =
18701895
let (|ConstructorPats|) pats =
18711896
match pats with
18721897
| SynArgPats.Pats ps -> ps
1873-
| SynArgPats.NamePatPairs(pats = xs) -> List.map (fun (_, _, pat) -> pat) xs
1898+
| SynArgPats.NamePatPairs(pats = xs) -> xs |> List.map _.Pattern
18741899

18751900
/// Returns all `Ident`s and `LongIdent`s found in an untyped AST.
18761901
let getLongIdents (parsedInput: ParsedInput) : IDictionary<pos, LongIdent> =

src/Compiler/Service/ServiceXmlDocParser.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module XmlDocParsing =
1616
let (|ConstructorPats|) =
1717
function
1818
| SynArgPats.Pats ps -> ps
19-
| SynArgPats.NamePatPairs(pats = xs) -> List.map (fun (_, _, pat) -> pat) xs
19+
| SynArgPats.NamePatPairs(pats = xs) -> xs |> List.map _.Pattern
2020

2121
let rec digNamesFrom pat =
2222
match pat with

src/Compiler/SyntaxTree/SyntaxTree.fs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -920,16 +920,37 @@ type SynSimplePats =
920920
match x with
921921
| SynSimplePats.SimplePats(range = range) -> range
922922

923+
[<NoEquality; NoComparison>]
924+
type NamePatPairField =
925+
| NamePatPairField of
926+
fieldName: SynLongIdent *
927+
equalsRange: range option *
928+
range: range *
929+
pat: SynPat *
930+
blockSeparator: BlockSeparator option
931+
932+
member this.FieldName =
933+
match this with
934+
| NamePatPairField(fieldName = n) -> n
935+
936+
member this.Range =
937+
match this with
938+
| NamePatPairField(range = m) -> m
939+
940+
member this.Pattern =
941+
match this with
942+
| NamePatPairField(pat = pat) -> pat
943+
923944
[<RequireQualifiedAccess>]
924945
type SynArgPats =
925946
| Pats of pats: SynPat list
926947

927-
| NamePatPairs of pats: (Ident * range option * SynPat) list * range: range * trivia: SynArgPatsNamePatPairsTrivia
948+
| NamePatPairs of pats: NamePatPairField list * range: range * trivia: SynArgPatsNamePatPairsTrivia
928949

929950
member x.Patterns =
930951
match x with
931952
| Pats pats -> pats
932-
| NamePatPairs(pats = pats) -> pats |> List.map (fun (_, _, pat) -> pat)
953+
| NamePatPairs(pats = pats) -> pats |> List.map _.Pattern
933954

934955
[<NoEquality; NoComparison; RequireQualifiedAccess>]
935956
type SynPat =
@@ -966,7 +987,7 @@ type SynPat =
966987

967988
| ArrayOrList of isArray: bool * elementPats: SynPat list * range: range
968989

969-
| Record of fieldPats: ((LongIdent * Ident) * range option * SynPat) list * range: range
990+
| Record of fieldPats: NamePatPairField list * range: range
970991

971992
| Null of range: range
972993

src/Compiler/SyntaxTree/SyntaxTree.fsi

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,12 +1046,36 @@ type SynSimplePats =
10461046

10471047
member Range: range
10481048

1049+
/// Represents a single named argument pattern a pair of the form `name = pattern`.
1050+
[<NoEquality; NoComparison>]
1051+
type NamePatPairField =
1052+
| NamePatPairField of
1053+
/// The identifier of the named field/parameter.
1054+
fieldName: SynLongIdent *
1055+
/// The range of the equals sign in `name = pattern`, if present.
1056+
equalsRange: range option *
1057+
/// The overall range of this name–pattern pair. Starts with `fieldName`'s range and ends with `pat`s range.
1058+
range: range *
1059+
/// The pattern associated with the named field.
1060+
pat: SynPat *
1061+
/// The separator trivia that follows this pair (e.g., semicolon or block separator), if any.
1062+
blockSeparator: BlockSeparator option
1063+
1064+
/// Gets the identifier of the named field/parameter.
1065+
member FieldName: SynLongIdent
1066+
1067+
/// Gets the overall range of this name–pattern pair, if available.
1068+
member Range: range
1069+
1070+
/// Gets the pattern associated with the named field.
1071+
member Pattern: SynPat
1072+
10491073
/// Represents a syntax tree for arguments patterns
10501074
[<RequireQualifiedAccess>]
10511075
type SynArgPats =
10521076
| Pats of pats: SynPat list
10531077

1054-
| NamePatPairs of pats: (Ident * range option * SynPat) list * range: range * trivia: SynArgPatsNamePatPairsTrivia
1078+
| NamePatPairs of pats: NamePatPairField list * range: range * trivia: SynArgPatsNamePatPairsTrivia
10551079

10561080
member Patterns: SynPat list
10571081

@@ -1105,7 +1129,7 @@ type SynPat =
11051129
| ArrayOrList of isArray: bool * elementPats: SynPat list * range: range
11061130

11071131
/// A record pattern
1108-
| Record of fieldPats: ((LongIdent * Ident) * range option * SynPat) list * range: range
1132+
| Record of fieldPats: NamePatPairField list * range: range
11091133

11101134
/// The 'null' pattern
11111135
| Null of range: range

0 commit comments

Comments
 (0)