Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
1799aaf
make attribute targets mismatches a warning and not an error.
edgarfgp Apr 23, 2025
55507e9
release notes
edgarfgp Apr 23, 2025
1738018
update tests
edgarfgp Apr 23, 2025
65f5bb6
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 24, 2025
0c97b9d
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 27, 2025
6f2b706
update baselines
edgarfgp Apr 29, 2025
e8f1bb0
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 29, 2025
75d8f5e
Update baselines
edgarfgp Apr 29, 2025
4f2e97e
Merge branch 'fix-attr-targets' of github.com:edgarfgp/fsharp into fi…
edgarfgp Apr 29, 2025
63be5d5
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 30, 2025
4248f2a
Move attribute form logic to an AP
edgarfgp Apr 30, 2025
cc96217
Merge branch 'main' into fix-attr-targets
edgarfgp May 1, 2025
e270b88
Merge branch 'main' into fix-attr-targets
edgarfgp May 1, 2025
e0cc65a
Merge branch 'main' into fix-attr-targets
edgarfgp May 2, 2025
1e29d58
Merge branch 'main' into fix-attr-targets
edgarfgp May 5, 2025
1470bf9
Merge branch 'main' into fix-attr-targets
edgarfgp May 6, 2025
8988215
Merge branch 'main' into fix-attr-targets
edgarfgp May 7, 2025
74712e8
Merge branch 'main' into fix-attr-targets
edgarfgp May 12, 2025
967c4a9
Merge branch 'main' of github.com:edgarfgp/fsharp
edgarfgp May 13, 2025
a30cef4
Merge branch 'dotnet:main' into main
edgarfgp May 22, 2025
5fa0480
Merge branch 'dotnet:main' into main
edgarfgp May 24, 2025
15e3d34
Merge branch 'dotnet:main' into main
edgarfgp May 29, 2025
b7ffcf8
Merge branch 'dotnet:main' into main
edgarfgp Jun 6, 2025
5bde641
Merge branch 'dotnet:main' into main
edgarfgp Jul 26, 2025
0f7c23c
Merge branch 'dotnet:main' into main
edgarfgp Jul 29, 2025
6a6843c
Merge branch 'dotnet:main' into main
edgarfgp Aug 4, 2025
d11dd4a
Merge branch 'dotnet:main' into main
edgarfgp Aug 4, 2025
30fc9a2
Merge branch 'dotnet:main' into main
edgarfgp Aug 5, 2025
815c51b
Merge branch 'dotnet:main' into main
edgarfgp Aug 11, 2025
7536249
Merge branch 'dotnet:main' into main
edgarfgp Aug 12, 2025
b7a0a41
Parser: capture named field separators
edgarfgp Aug 18, 2025
a2b1fcf
udpate bsl
edgarfgp Aug 18, 2025
9e7bb64
ILVerify
edgarfgp Aug 18, 2025
fbd29c9
Merge branch 'main' into capture-named-fields-block-separators
edgarfgp Aug 18, 2025
73ce649
release notes
edgarfgp Aug 18, 2025
1937367
Merge branch 'capture-named-fields-block-separators' of github.com:ed…
edgarfgp Aug 18, 2025
1830711
Trying to fix editor test
edgarfgp Aug 18, 2025
da51899
Capture also block separators in SynPat.Record
edgarfgp Aug 19, 2025
1aff181
update baselines
edgarfgp Aug 19, 2025
47a67bd
Update SyntaxTree tests
edgarfgp Aug 19, 2025
01c97a9
format code
edgarfgp Aug 19, 2025
c5e9040
ILVerify
edgarfgp Aug 19, 2025
2e0ed54
fix editor test
edgarfgp Aug 19, 2025
26a86f6
fotmat code
edgarfgp Aug 19, 2025
4a04c1e
Revert "fix editor test"
edgarfgp Aug 19, 2025
fc87381
fix editor test
edgarfgp Aug 19, 2025
89e95dc
Revert "fix editor test"
edgarfgp Aug 19, 2025
7f7d963
Add fieldPath to NamePatPairField
edgarfgp Aug 20, 2025
89fdc29
ilverify
edgarfgp Aug 20, 2025
32a1101
Update ServiceParseWalk.fs
edgarfgp Aug 21, 2025
0cfe5ea
Merge branch 'capture-named-fields-block-separators' of github.com:ed…
edgarfgp Aug 21, 2025
532955c
fix completion test
edgarfgp Aug 21, 2025
6d94ade
Try using SynLongIdent
edgarfgp Aug 22, 2025
842214e
Merge branch 'main' into capture-named-fields-block-separators
edgarfgp Aug 25, 2025
2c1ac7d
Merge branch 'main' into capture-named-fields-block-separators
edgarfgp Aug 25, 2025
c4f9272
Merge branch 'main' into capture-named-fields-block-separators
edgarfgp Aug 25, 2025
5e32e95
NamePatPairField range should not be optional
edgarfgp Aug 26, 2025
f9dc90c
Merge branch 'capture-named-fields-block-separators' of github.com:ed…
edgarfgp Aug 26, 2025
7c4375c
Merge branch 'main' into capture-named-fields-block-separators
edgarfgp Aug 26, 2025
a1c7d2f
Merge branch 'main' into capture-named-fields-block-separators
edgarfgp Aug 26, 2025
7afe4b1
ILVerify
edgarfgp Aug 26, 2025
e0e5e2d
tests to show case when = is not present
edgarfgp Aug 26, 2025
ec60f7e
remove duplicated rule
edgarfgp Aug 26, 2025
2c15fc9
Update src/Compiler/SyntaxTree/SyntaxTree.fsi
edgarfgp Aug 26, 2025
07bafb6
Merge branch 'main' into capture-named-fields-block-separators
edgarfgp Aug 26, 2025
39e4348
Revert "remove duplicated rule"
edgarfgp Aug 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/10.0.100.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

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

### Breaking Changes
Expand Down
18 changes: 15 additions & 3 deletions src/Compiler/Checking/CheckPatterns.fs
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,13 @@ and TcPatArrayOrList warnOnUpper cenv env vFlags patEnv ty isArray args m =
phase2, acc

and TcRecordPat warnOnUpper (cenv: cenv) env vFlags patEnv ty fieldPats m =
let fieldPats = fieldPats |> List.map (fun (fieldId, _, fieldPat) -> fieldId, fieldPat)
let fieldPats =
fieldPats
|> List.map (fun (NamePatPairField(fieldName = fieldLid; pat = pat)) ->
match fieldLid.LongIdent with
| [id] -> ([], id), pat
| lid -> List.frontAndBack lid, pat)

match BuildFieldMap cenv env false ty fieldPats m with
| None -> (fun _ -> TPat_error m), patEnv
| Some(tinst, tcref, fldsmap, _fldsList) ->
Expand Down Expand Up @@ -503,7 +509,9 @@ and CheckNoArgsForLiteral args m =
and GetSynArgPatterns args =
match args with
| SynArgPats.Pats args -> args
| SynArgPats.NamePatPairs (pats = pairs) -> List.map (fun (_, _, pat) -> pat) pairs
| SynArgPats.NamePatPairs (pats = pairs) ->
pairs
|> List.map _.Pattern

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

for id, _, pat in pairs do
for NamePatPairField(fieldName = fieldLid; pat = pat) in pairs do
let id =
match fieldLid.LongIdent with
| [id] -> id
| lid -> snd (List.frontAndBack lid)
match argNames |> List.tryFindIndex (fun id2 -> id.idText = id2.Id.idText) with
| None ->
extraPatterns.Add pat
Expand Down
19 changes: 4 additions & 15 deletions src/Compiler/Driver/GraphChecking/FileContentMapping.fs
Original file line number Diff line number Diff line change
Expand Up @@ -622,20 +622,9 @@ let visitPat (p: SynPat) : FileContentEntry list =
let continuations = List.map visit elementPats
Continuation.concatenate continuations continuation
| SynPat.Record(fieldPats, _) ->
let pats = List.map (fun (_, _, p) -> p) fieldPats

let lids =
[
for (l, _), _, _ in fieldPats do
yield! visitLongIdent l
]

let pats = fieldPats |> List.map (fun f -> f.Pattern)
let continuations = List.map visit pats

let finalContinuation nodes =
[ yield! List.concat nodes; yield! lids ] |> continuation

Continuation.sequence continuations finalContinuation
Continuation.concatenate continuations continuation
| SynPat.Null _ -> continuation []
| SynPat.OptionalVal _ -> continuation []
| SynPat.IsInst(t, _) -> continuation (visitSynType t)
Expand All @@ -650,8 +639,8 @@ let visitSynArgPats (argPat: SynArgPats) =
| SynArgPats.Pats args -> List.collect visitPat args
| SynArgPats.NamePatPairs(pats = pats) ->
[
for _, _, p in pats do
yield! visitPat p
for p in pats do
yield! visitPat p.Pattern
]

let visitSynSimplePat (pat: SynSimplePat) =
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/Service/ServiceParseTreeWalk.fs
Original file line number Diff line number Diff line change
Expand Up @@ -772,15 +772,15 @@ module SyntaxTraversal =
| SynPat.Ands(ps, _)
| SynPat.Tuple(elementPats = ps)
| SynPat.ArrayOrList(_, ps, _) -> ps |> List.tryPick (traversePat path)
| SynPat.Record(fieldPats = fieldPats) -> fieldPats |> List.tryPick (fun (_, _, p) -> traversePat path p)
| SynPat.Record(fieldPats = fieldPats) -> fieldPats |> List.tryPick (fun x -> traversePat path x.Pattern)
| SynPat.Attrib(p, attributes, m) ->
match traversePat path p with
| None -> attributeApplicationDives path attributes |> pick m attributes
| x -> x
| SynPat.LongIdent(argPats = args) ->
match args with
| SynArgPats.Pats ps -> ps |> List.tryPick (traversePat path)
| SynArgPats.NamePatPairs(pats = ps) -> ps |> List.map (fun (_, _, pat) -> pat) |> List.tryPick (traversePat path)
| SynArgPats.NamePatPairs(pats = ps) -> ps |> List.tryPick (fun x -> traversePat path x.Pattern)
| SynPat.Typed(p, ty, _) ->
match traversePat path p with
| None -> traverseSynType path ty
Expand Down
53 changes: 39 additions & 14 deletions src/Compiler/Service/ServiceParsedInputOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ module ParsedInput =
let (|ConstructorPats|) pats =
match pats with
| SynArgPats.Pats ps -> ps
| SynArgPats.NamePatPairs(pats = xs) -> List.map (fun (_, _, pat) -> pat) xs
| SynArgPats.NamePatPairs(pats = xs) -> xs |> List.map _.Pattern

let inline isPosInRange range = rangeContainsPos range pos

Expand Down Expand Up @@ -1120,6 +1120,8 @@ module ParsedInput =
let last = List.last lid.LongIdent
last.idRange.End

let lastIdentOfSynLongIdent (lid: SynLongIdent) = List.last lid.LongIdent

let endOfClosingTokenOrLastIdent (mClosing: range option) (lid: SynLongIdent) =
match mClosing with
| Some m -> m.End
Expand Down Expand Up @@ -1293,18 +1295,24 @@ module ParsedInput =
rangeContainsPos m pos
->
pats
|> List.tryPick (fun (fieldId, _, pat) ->
if rangeContainsPos fieldId.idRange pos then
let referencedFields = pats |> List.map (fun (id, _, _) -> id.idText)
|> List.tryPick (fun field ->
if rangeContainsPos field.FieldName.Range pos then
let referencedFields =
pats |> List.map (fun f -> (lastIdentOfSynLongIdent f.FieldName).idText)

Some(CompletionContext.Pattern(PatternContext.UnionCaseFieldIdentifier(referencedFields, caseId.Range)))
else
let context = Some(PatternContext.NamedUnionCaseField(fieldId.idText, caseId.Range))
TryGetCompletionContextInPattern suppressIdentifierCompletions pat context pos)
let lastId = lastIdentOfSynLongIdent field.FieldName
let context = Some(PatternContext.NamedUnionCaseField(lastId.idText, caseId.Range))

TryGetCompletionContextInPattern suppressIdentifierCompletions field.Pattern context pos)
|> Option.orElseWith (fun () ->
// Last resort - check for fun (Case (item1 = a; | )) ->
// That is, pos is after the last pair and still within parentheses
if rangeBeforePos mPairs pos then
let referencedFields = pats |> List.map (fun (id, _, _) -> id.idText)
let referencedFields =
pats |> List.map (fun f -> (lastIdentOfSynLongIdent f.FieldName).idText)

Some(CompletionContext.Pattern(PatternContext.UnionCaseFieldIdentifier(referencedFields, caseId.Range)))
else
None)
Expand Down Expand Up @@ -1335,9 +1343,17 @@ module ParsedInput =
|> List.tryPick (fun pat -> TryGetCompletionContextInPattern false pat None pos)
| SynPat.Record(fieldPats = pats; range = m) when rangeContainsPos m pos ->
pats
|> List.tryPick (fun ((_, fieldId), _, pat) ->
if rangeContainsPos fieldId.idRange pos then
let referencedFields = pats |> List.map (fun ((_, x), _, _) -> x.idText, x.idRange)
|> List.tryPick (fun f ->
let fieldId = f.FieldName
let pat = f.Pattern

if rangeContainsPos fieldId.Range pos then
let referencedFields =
pats
|> List.map (fun f ->
let lastId = lastIdentOfSynLongIdent f.FieldName
lastId.idText, lastId.idRange)

Some(CompletionContext.Pattern(PatternContext.RecordFieldIdentifier referencedFields))
elif rangeContainsPos pat.Range pos then
TryGetCompletionContextInPattern false pat None pos
Expand All @@ -1348,13 +1364,22 @@ module ParsedInput =
// That is, pos is after the last field and still within braces
if
pats
|> List.forall (fun (_, mEquals, pat) ->
match mEquals, pat with
|> List.forall (fun f ->
let mEqualsOpt =
match f with
| NamePatPairField(equalsRange = m) -> m

match mEqualsOpt, f.Pattern with
| Some mEquals, SynPat.Wild mPat -> rangeBeforePos mEquals pos && mPat.StartColumn <> mPat.EndColumn
| Some mEquals, _ -> rangeBeforePos mEquals pos
| _ -> false)
then
let referencedFields = pats |> List.map (fun ((_, x), _, _) -> x.idText, x.idRange)
let referencedFields =
pats
|> List.map (fun f ->
let lastId = lastIdentOfSynLongIdent f.FieldName
lastId.idText, lastId.idRange)

Some(CompletionContext.Pattern(PatternContext.RecordFieldIdentifier referencedFields))
else
Some(CompletionContext.Pattern PatternContext.Other))
Expand Down Expand Up @@ -1870,7 +1895,7 @@ module ParsedInput =
let (|ConstructorPats|) pats =
match pats with
| SynArgPats.Pats ps -> ps
| SynArgPats.NamePatPairs(pats = xs) -> List.map (fun (_, _, pat) -> pat) xs
| SynArgPats.NamePatPairs(pats = xs) -> xs |> List.map _.Pattern

/// Returns all `Ident`s and `LongIdent`s found in an untyped AST.
let getLongIdents (parsedInput: ParsedInput) : IDictionary<pos, LongIdent> =
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Service/ServiceXmlDocParser.fs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module XmlDocParsing =
let (|ConstructorPats|) =
function
| SynArgPats.Pats ps -> ps
| SynArgPats.NamePatPairs(pats = xs) -> List.map (fun (_, _, pat) -> pat) xs
| SynArgPats.NamePatPairs(pats = xs) -> xs |> List.map _.Pattern

let rec digNamesFrom pat =
match pat with
Expand Down
27 changes: 24 additions & 3 deletions src/Compiler/SyntaxTree/SyntaxTree.fs
Original file line number Diff line number Diff line change
Expand Up @@ -920,16 +920,37 @@ type SynSimplePats =
match x with
| SynSimplePats.SimplePats(range = range) -> range

[<NoEquality; NoComparison>]
type NamePatPairField =
| NamePatPairField of
fieldName: SynLongIdent *
equalsRange: range option *
range: range *
pat: SynPat *
blockSeparator: BlockSeparator option

member this.FieldName =
match this with
| NamePatPairField(fieldName = n) -> n

member this.Range =
match this with
| NamePatPairField(range = m) -> m

member this.Pattern =
match this with
| NamePatPairField(pat = pat) -> pat

[<RequireQualifiedAccess>]
type SynArgPats =
| Pats of pats: SynPat list

| NamePatPairs of pats: (Ident * range option * SynPat) list * range: range * trivia: SynArgPatsNamePatPairsTrivia
| NamePatPairs of pats: NamePatPairField list * range: range * trivia: SynArgPatsNamePatPairsTrivia

member x.Patterns =
match x with
| Pats pats -> pats
| NamePatPairs(pats = pats) -> pats |> List.map (fun (_, _, pat) -> pat)
| NamePatPairs(pats = pats) -> pats |> List.map _.Pattern

[<NoEquality; NoComparison; RequireQualifiedAccess>]
type SynPat =
Expand Down Expand Up @@ -966,7 +987,7 @@ type SynPat =

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

| Record of fieldPats: ((LongIdent * Ident) * range option * SynPat) list * range: range
| Record of fieldPats: NamePatPairField list * range: range

| Null of range: range

Expand Down
28 changes: 26 additions & 2 deletions src/Compiler/SyntaxTree/SyntaxTree.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -1046,12 +1046,36 @@ type SynSimplePats =

member Range: range

/// Represents a single named argument pattern a pair of the form `name = pattern`.
[<NoEquality; NoComparison>]
type NamePatPairField =
| NamePatPairField of
/// The identifier of the named field/parameter.
fieldName: SynLongIdent *
/// The range of the equals sign in `name = pattern`, if present.
equalsRange: range option *
/// The overall range of this name–pattern pair. Starts with `fieldName`'s range and ends with `pat`s range.
range: range *
/// The pattern associated with the named field.
pat: SynPat *
/// The separator trivia that follows this pair (e.g., semicolon or block separator), if any.
blockSeparator: BlockSeparator option

/// Gets the identifier of the named field/parameter.
member FieldName: SynLongIdent

/// Gets the overall range of this name–pattern pair, if available.
member Range: range

/// Gets the pattern associated with the named field.
member Pattern: SynPat

/// Represents a syntax tree for arguments patterns
[<RequireQualifiedAccess>]
type SynArgPats =
| Pats of pats: SynPat list

| NamePatPairs of pats: (Ident * range option * SynPat) list * range: range * trivia: SynArgPatsNamePatPairsTrivia
| NamePatPairs of pats: NamePatPairField list * range: range * trivia: SynArgPatsNamePatPairsTrivia

member Patterns: SynPat list

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

/// A record pattern
| Record of fieldPats: ((LongIdent * Ident) * range option * SynPat) list * range: range
| Record of fieldPats: NamePatPairField list * range: range

/// The 'null' pattern
| Null of range: range
Expand Down
Loading
Loading