From 9f8f37ff039e7b7e58943c4065fa7d9cd4ae27d1 Mon Sep 17 00:00:00 2001 From: kerams Date: Wed, 30 Aug 2023 18:50:22 +0200 Subject: [PATCH 1/4] Filter completions for record fields in patterns --- src/Compiler/Service/FSharpCheckerResults.fs | 276 +++++++++--------- src/Compiler/Service/ServiceParsedInputOps.fs | 23 +- .../Service/ServiceParsedInputOps.fsi | 3 + src/Compiler/TypedTree/TypedTree.fs | 4 +- src/Compiler/TypedTree/TypedTree.fsi | 4 +- .../CompletionProviderTests.fs | 40 ++- 6 files changed, 198 insertions(+), 152 deletions(-) diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index a75c52cf45..e734bf2cfd 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -800,6 +800,28 @@ type internal TypeCheckInfo | Item.Types (_, ty :: _) when isInterfaceTy g ty -> true | _ -> false + /// Is the item suitable for completion in a pattern + let IsPatternCandidate (item: CompletionItem) = + match item.Item with + | Item.Value v -> v.LiteralValue.IsSome + | Item.ILField field -> field.LiteralValue.IsSome + | Item.ActivePatternCase _ + | Item.ExnCase _ + | Item.ModuleOrNamespaces _ + | Item.Types _ + | Item.UnionCase _ -> true + | _ -> false + + /// Is the item suitable for completion in a type application or type annotation + let IsTypeCandidate (item: CompletionItem) = + match item.Item with + | Item.ModuleOrNamespaces _ + | Item.Types _ + | Item.TypeVar _ + | Item.UnqualifiedType _ + | Item.ExnCase _ -> true + | _ -> false + /// Return only items with the specified name, modulo "Attribute" for type completions let FilterDeclItemsByResidue (getItem: 'a -> Item) residue (items: 'a list) = let attributedResidue = residue + "Attribute" @@ -939,6 +961,10 @@ type internal TypeCheckInfo Unresolved = None } + let getItem (x: ItemWithInst) = x.Item + + let getItem2 (x: CompletionItem) = x.Item + /// Checks whether the suggested name is unused. /// In the future we could use an increasing numeric suffix for conflict resolution let CreateCompletionItemForSuggestedPatternName (pos: pos) name = @@ -1044,7 +1070,7 @@ type internal TypeCheckInfo |> List.map (fun (name, overloads) -> Item.MethodGroup(name, overloads, None) |> ItemWithNoInst - |> CompletionItem ValueNone ValueNone) + |> DefaultCompletionItem) Some(overridableMethods, nenv.DisplayEnv, m) | _ -> None) @@ -1063,12 +1089,74 @@ type internal TypeCheckInfo else Item.UnionCaseField(uci, index) |> ItemWithNoInst - |> CompletionItem ValueNone ValueNone + |> DefaultCompletionItem |> Some) |> Some | _ -> None) - let getItem (x: ItemWithInst) = x.Item + let GetCompletionsForUnionCaseField pos indexOrName caseIdRange isTheOnlyField declaredItems = + let declaredItems = + declaredItems + |> Option.bind (FilterRelevantItemsBy getItem2 None IsPatternCandidate) + + // When the user types `fun (Case (x| )) ->`, we do not yet know whether the intention is to use positional or named arguments, + // so let's show options for both. + let fields indexOrName isTheOnlyField (uci: UnionCaseInfo) = + match indexOrName, isTheOnlyField with + | Choice1Of2 (Some 0), true -> + uci.UnionCase.RecdFields + |> List.mapi (fun index _ -> Item.UnionCaseField(uci, index) |> ItemWithNoInst |> DefaultCompletionItem) + | _ -> [] + + sResolutions.CapturedNameResolutions + |> ResizeArray.tryPick (fun r -> + match r.Item with + | Item.UnionCase (uci, _) when equals r.Range caseIdRange -> + let list = + declaredItems + |> Option.map p13 + |> Option.defaultValue [] + |> List.append (fields indexOrName isTheOnlyField uci) + + Some(SuggestNameForUnionCaseFieldPattern g caseIdRange.End pos uci indexOrName list, r.DisplayEnv, r.Range) + | _ -> None) + |> Option.orElse declaredItems + + let GetCompletionsForRecordField pos (referencedFields: Ident list) declaredItems = + declaredItems + |> Option.map (fun (items: CompletionItem list, denv, range) -> + let fields = + // Try to find a name resolution for any of the referenced fields, and through it access all available fields of the record + referencedFields + |> List.tryPick (fun fieldId -> + sResolutions.CapturedNameResolutions + |> ResizeArray.tryPick (fun cnr -> + match cnr.Item with + | Item.RecdField info when equals cnr.Range fieldId.idRange -> + info.TyconRef.AllFieldAsRefList + |> List.choose (fun field -> + if referencedFields |> List.exists (fun x -> x.idText = field.DisplayName) then + None + else + FreshenRecdFieldRef ncenv field.Range field |> Item.RecdField |> Some) + |> Some + | _ -> None)) + |> Option.defaultWith (fun () -> + // Fall back to showing all record field names in scope + let (nenv, _), _ = GetBestEnvForPos pos + getRecordFieldsInScope nenv) + |> List.map (ItemWithNoInst >> DefaultCompletionItem) + + let items = + items + |> List.filter (fun item -> + match item.Item with + | Item.ModuleOrNamespaces _ -> true + | Item.Types (_, ty :: _) -> isRecdTy g ty + | _ -> false) + |> List.append fields + + items, denv, range) let GetDeclaredItems ( @@ -1316,6 +1404,22 @@ type internal TypeCheckInfo | atStart when atStart = 0 -> 0 | otherwise -> otherwise - 1 + let getDeclaredItemsNotInRangeOpWithAllSymbols () = + GetDeclaredItems( + parseResultsOpt, + lineStr, + origLongIdentOpt, + colAtEndOfNamesAndResidue, + residueOpt, + lastDotPos, + line, + loc, + filterCtors, + resolveOverloads, + false, + getAllSymbols + ) + let pos = mkPos line colAtEndOfNamesAndResidue // Look for a "special" completion context @@ -1445,21 +1549,7 @@ type internal TypeCheckInfo | Some (CompletionContext.ParameterList (endPos, fields)) -> let results = GetNamedParametersAndSettableFields endPos - let declaredItems = - GetDeclaredItems( - parseResultsOpt, - lineStr, - origLongIdentOpt, - colAtEndOfNamesAndResidue, - residueOpt, - lastDotPos, - line, - loc, - filterCtors, - resolveOverloads, - false, - getAllSymbols - ) + let declaredItems = getDeclaredItemsNotInRangeOpWithAllSymbols () match results with | NameResResult.Members (items, denv, m) -> @@ -1484,20 +1574,7 @@ type internal TypeCheckInfo | _ -> declaredItems | Some (CompletionContext.AttributeApplication) -> - GetDeclaredItems( - parseResultsOpt, - lineStr, - origLongIdentOpt, - colAtEndOfNamesAndResidue, - residueOpt, - lastDotPos, - line, - loc, - filterCtors, - resolveOverloads, - false, - getAllSymbols - ) + getDeclaredItemsNotInRangeOpWithAllSymbols () |> Option.map (fun (items, denv, m) -> items |> List.filter (fun cItem -> @@ -1509,20 +1586,7 @@ type internal TypeCheckInfo m) | Some (CompletionContext.OpenDeclaration isOpenType) -> - GetDeclaredItems( - parseResultsOpt, - lineStr, - origLongIdentOpt, - colAtEndOfNamesAndResidue, - residueOpt, - lastDotPos, - line, - loc, - filterCtors, - resolveOverloads, - false, - getAllSymbols - ) + getDeclaredItemsNotInRangeOpWithAllSymbols () |> Option.map (fun (items, denv, m) -> items |> List.filter (fun x -> @@ -1541,108 +1605,28 @@ type internal TypeCheckInfo | Some CompletionContext.TypeAbbreviationOrSingleCaseUnion // Completion at 'Field1: ...' | Some (CompletionContext.RecordField (RecordContext.Declaration false)) -> - GetDeclaredItems( - parseResultsOpt, - lineStr, - origLongIdentOpt, - colAtEndOfNamesAndResidue, - residueOpt, - lastDotPos, - line, - loc, - filterCtors, - resolveOverloads, - false, - getAllSymbols - ) - |> Option.map (fun (items, denv, m) -> - items - |> List.filter (fun cItem -> - match cItem.Item with - | Item.ModuleOrNamespaces _ - | Item.Types _ - | Item.TypeVar _ - | Item.UnqualifiedType _ - | Item.ExnCase _ -> true - | _ -> false), - denv, - m) - - | Some (CompletionContext.Pattern (PatternContext.UnionCaseFieldIdentifier (referencedFields, caseIdRange))) -> - GetUnionCaseFields caseIdRange referencedFields - |> Option.map (fun completions -> - let (nenv, _ad), m = GetBestEnvForPos pos - completions, nenv.DisplayEnv, m) + getDeclaredItemsNotInRangeOpWithAllSymbols () + |> Option.bind (FilterRelevantItemsBy getItem2 None IsTypeCandidate) | Some (CompletionContext.Pattern patternContext) -> - let declaredItems = - GetDeclaredItems( - parseResultsOpt, - lineStr, - origLongIdentOpt, - colAtEndOfNamesAndResidue, - residueOpt, - lastDotPos, - line, - loc, - filterCtors, - resolveOverloads, - false, - getAllSymbols - ) - |> Option.map (fun (items, denv, range) -> - let filtered = - items - |> List.filter (fun item -> - match item.Item with - | Item.Value v -> v.LiteralValue.IsSome - | Item.ILField field -> field.LiteralValue.IsSome - | Item.ActivePatternCase _ - | Item.ExnCase _ - | Item.ModuleOrNamespaces _ - | Item.NewDef _ - | Item.Types _ - | Item.UnionCase _ -> true - | _ -> false) - - filtered, denv, range) - - let indexOrName, caseIdRange = - match patternContext with - | PatternContext.PositionalUnionCaseField (index, _, m) -> Choice1Of2 index, m - | PatternContext.NamedUnionCaseField (name, m) -> Choice2Of2 name, m - | PatternContext.UnionCaseFieldIdentifier _ - | PatternContext.Other -> Choice1Of2 None, range0 - - // No special handling other than filtering out items that may not appear in a pattern - if equals caseIdRange range0 then - declaredItems - else - // When the user types `fun (Case (x| )) ->`, we do not yet know whether the intention is to use positional or named arguments, - // so let's show options for both. - let fields patternContext (uci: UnionCaseInfo) = - match patternContext with - | PatternContext.PositionalUnionCaseField (Some 0, true, _) -> - uci.UnionCase.RecdFields - |> List.mapi (fun index _ -> - Item.UnionCaseField(uci, index) - |> ItemWithNoInst - |> CompletionItem ValueNone ValueNone) - | _ -> [] - - sResolutions.CapturedNameResolutions - |> ResizeArray.tryPick (fun r -> - match r.Item with - | Item.UnionCase (uci, _) when equals r.Range caseIdRange -> - let list = - declaredItems - |> Option.map p13 - |> Option.defaultValue [] - |> List.append (fields patternContext uci) - - Some(SuggestNameForUnionCaseFieldPattern g caseIdRange.End pos uci indexOrName list, r.DisplayEnv, r.Range) - | _ -> None) - |> Option.orElse declaredItems + match patternContext with + | PatternContext.UnionCaseFieldIdentifier (referencedFields, caseIdRange) -> + GetUnionCaseFields caseIdRange referencedFields + |> Option.map (fun completions -> + let (nenv, _ad), m = GetBestEnvForPos pos + completions, nenv.DisplayEnv, m) + | PatternContext.PositionalUnionCaseField (fieldIndex, isTheOnlyField, caseIdRange) -> + getDeclaredItemsNotInRangeOpWithAllSymbols () + |> GetCompletionsForUnionCaseField pos (Choice1Of2 fieldIndex) caseIdRange isTheOnlyField + | PatternContext.NamedUnionCaseField (fieldName, caseIdRange) -> + getDeclaredItemsNotInRangeOpWithAllSymbols () + |> GetCompletionsForUnionCaseField pos (Choice2Of2 fieldName) caseIdRange false + | PatternContext.RecordFieldIdentifier referencedFields -> + getDeclaredItemsNotInRangeOpWithAllSymbols () + |> GetCompletionsForRecordField pos referencedFields + | PatternContext.Other -> + getDeclaredItemsNotInRangeOpWithAllSymbols () + |> Option.bind (FilterRelevantItemsBy getItem2 None IsPatternCandidate) | Some (CompletionContext.MethodOverride enclosingTypeNameRange) -> GetOverridableMethods pos enclosingTypeNameRange diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index 2a292e9763..b93b10fc1e 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -64,6 +64,9 @@ type PatternContext = /// Completing union case field identifier in a pattern (e.g. fun (Case (field1 = a; fie| )) -> ) | UnionCaseFieldIdentifier of referencedFields: string list * caseIdRange: range + /// Completing a record field identifier in a pattern (e.g. fun { Field1 = a; Fie| } -> ) + | RecordFieldIdentifier of referencedFields: Ident list + /// Any other position in a pattern that does not need special handling | Other @@ -1310,10 +1313,28 @@ module ParsedInput = | _ -> pats |> List.tryPick (fun pat -> TryGetCompletionContextInPattern false pat None pos) + | SynPat.Record (fieldPats = pats) -> + pats + |> List.tryPick (fun ((_, fieldId), _, pat) -> + if rangeContainsPos fieldId.idRange pos then + let referencedFields = pats |> List.map (fun ((_, x), _, _) -> x) + Some(CompletionContext.Pattern(PatternContext.RecordFieldIdentifier referencedFields)) + elif rangeContainsPos pat.Range pos then + TryGetCompletionContextInPattern false pat None pos + else + None) + |> Option.orElseWith (fun () -> + // Last resort - check for fun { Field1 = a; F| } -> + // That is, pos is after the last field and still within braces + if pats |> List.forall (fun (_, m, _) -> rangeBeforePos m pos) then + let referencedFields = pats |> List.map (fun ((_, x), _, _) -> x) + Some(CompletionContext.Pattern(PatternContext.RecordFieldIdentifier referencedFields)) + else + None) | SynPat.Ands (pats = pats) | SynPat.ArrayOrList (elementPats = pats) -> pats - |> List.tryPick (fun pat -> TryGetCompletionContextInPattern suppressIdentifierCompletions pat None pos) + |> List.tryPick (fun pat -> TryGetCompletionContextInPattern false pat None pos) | SynPat.Tuple (elementPats = pats; commaRanges = commas; range = m) -> pats |> List.indexed diff --git a/src/Compiler/Service/ServiceParsedInputOps.fsi b/src/Compiler/Service/ServiceParsedInputOps.fsi index 877ca64a7f..8e2433415b 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fsi +++ b/src/Compiler/Service/ServiceParsedInputOps.fsi @@ -36,6 +36,9 @@ type public PatternContext = /// Completing union case field identifier in a pattern (e.g. fun (Case (field1 = a; fie| )) -> ) | UnionCaseFieldIdentifier of referencedFields: string list * caseIdRange: range + /// Completing a record field identifier in a pattern (e.g. fun { Field1 = a; Fie| } -> ) + | RecordFieldIdentifier of referencedFields: Ident list + /// Any other position in a pattern that does not need special handling | Other diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index a47b9db922..b82490c520 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -4142,7 +4142,7 @@ type UnionCaseRef = type RecdFieldRef = | RecdFieldRef of tyconRef: TyconRef * fieldName: string - /// Get a reference to the type containing this union case + /// Get a reference to the type containing this record field member x.TyconRef = let (RecdFieldRef(tcref, _)) = x in tcref /// Get the name of the field @@ -4151,7 +4151,7 @@ type RecdFieldRef = /// Get the name of the field, with backticks added for non-identifier names member x.DisplayName = x.FieldName |> ConvertLogicalNameToDisplayName - /// Get the Entity for the type containing this union case + /// Get the Entity for the type containing this record field member x.Tycon = x.TyconRef.Deref /// Dereference the reference diff --git a/src/Compiler/TypedTree/TypedTree.fsi b/src/Compiler/TypedTree/TypedTree.fsi index 72b7efb1f6..55af38d9b9 100644 --- a/src/Compiler/TypedTree/TypedTree.fsi +++ b/src/Compiler/TypedTree/TypedTree.fsi @@ -3001,10 +3001,10 @@ type RecdFieldRef = /// Try to dereference the reference member TryRecdField: RecdField voption - /// Get the Entity for the type containing this union case + /// Get the Entity for the type containing this record field member Tycon: Entity - /// Get a reference to the type containing this union case + /// Get a reference to the type containing this record field member TyconRef: TyconRef /// Represents a type in the typed abstract syntax diff --git a/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs index e8294caff8..487bb0d332 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs @@ -1763,7 +1763,7 @@ match U1 (1, A) with VerifyCompletionList(fileContents, "| U1 (x, y", [ "yyy"; "tab" ], [ "xxx"; "num"; "fff" ]) [] - let ``Completion list for union case field identifier contains available fields`` () = + let ``Completion list for union case field identifier in a pattern contains available fields`` () = let fileContents = """ type PatternContext = @@ -1921,3 +1921,41 @@ type C () = VerifyNoCompletionList(fileContents, "override a") VerifyNoCompletionList(fileContents, "override _") VerifyNoCompletionList(fileContents, "override c") + + [] + let ``Completion list for record field identifier in a pattern contains available fields, modules, namespaces and record types`` () = + let fileContents = + """ +open System + +type DU = + | X + +type R1 = { A: int; B: int } +type R2 = { C: int; D: int } + +match [] with +| [ { A = 2; l = 2 } ] +""" + + VerifyCompletionList( + fileContents, + "| [ { A = 2; l", + [ "B"; "R1"; "R2"; "System"; "LanguagePrimitives" ], + [ "A"; "C"; "D"; "DU"; "X"; "log"; "let"; "Lazy" ] + ) + + [] + let ``Completion list for record field identifier in a pattern contains fields of all records in scope when the record type is not known yet`` + () + = + let fileContents = + """ +type R1 = { A: int; B: int } +type R2 = { C: int; D: int } + +match { A = 1; B = 2 } with +| { f = () } +""" + + VerifyCompletionList(fileContents, "| { f = ()", [ "A"; "B"; "C"; "D" ], []) From e33c92a91afb1d6fe5b53ed9c1e8a3097be7170b Mon Sep 17 00:00:00 2001 From: kerams Date: Wed, 30 Aug 2023 20:46:06 +0200 Subject: [PATCH 2/4] Fix --- src/Compiler/Service/FSharpCheckerResults.fs | 8 ++++---- src/Compiler/Service/ServiceParsedInputOps.fs | 6 +++--- src/Compiler/Service/ServiceParsedInputOps.fsi | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index e734bf2cfd..a47b093702 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -1122,20 +1122,20 @@ type internal TypeCheckInfo | _ -> None) |> Option.orElse declaredItems - let GetCompletionsForRecordField pos (referencedFields: Ident list) declaredItems = + let GetCompletionsForRecordField pos referencedFields declaredItems = declaredItems |> Option.map (fun (items: CompletionItem list, denv, range) -> let fields = // Try to find a name resolution for any of the referenced fields, and through it access all available fields of the record referencedFields - |> List.tryPick (fun fieldId -> + |> List.tryPick (fun (_, fieldRange) -> sResolutions.CapturedNameResolutions |> ResizeArray.tryPick (fun cnr -> match cnr.Item with - | Item.RecdField info when equals cnr.Range fieldId.idRange -> + | Item.RecdField info when equals cnr.Range fieldRange -> info.TyconRef.AllFieldAsRefList |> List.choose (fun field -> - if referencedFields |> List.exists (fun x -> x.idText = field.DisplayName) then + if referencedFields |> List.exists (fun (fieldName, _) -> fieldName = field.DisplayName) then None else FreshenRecdFieldRef ncenv field.Range field |> Item.RecdField |> Some) diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index b93b10fc1e..c1d2d6e0c4 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -65,7 +65,7 @@ type PatternContext = | UnionCaseFieldIdentifier of referencedFields: string list * caseIdRange: range /// Completing a record field identifier in a pattern (e.g. fun { Field1 = a; Fie| } -> ) - | RecordFieldIdentifier of referencedFields: Ident list + | RecordFieldIdentifier of referencedFields: (string * range) list /// Any other position in a pattern that does not need special handling | Other @@ -1317,7 +1317,7 @@ module ParsedInput = pats |> List.tryPick (fun ((_, fieldId), _, pat) -> if rangeContainsPos fieldId.idRange pos then - let referencedFields = pats |> List.map (fun ((_, x), _, _) -> x) + let referencedFields = pats |> List.map (fun ((_, x), _, _) -> x.idText, x.idRange) Some(CompletionContext.Pattern(PatternContext.RecordFieldIdentifier referencedFields)) elif rangeContainsPos pat.Range pos then TryGetCompletionContextInPattern false pat None pos @@ -1327,7 +1327,7 @@ module ParsedInput = // Last resort - check for fun { Field1 = a; F| } -> // That is, pos is after the last field and still within braces if pats |> List.forall (fun (_, m, _) -> rangeBeforePos m pos) then - let referencedFields = pats |> List.map (fun ((_, x), _, _) -> x) + let referencedFields = pats |> List.map (fun ((_, x), _, _) -> x.idText, x.idRange) Some(CompletionContext.Pattern(PatternContext.RecordFieldIdentifier referencedFields)) else None) diff --git a/src/Compiler/Service/ServiceParsedInputOps.fsi b/src/Compiler/Service/ServiceParsedInputOps.fsi index 8e2433415b..5b8d877a80 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fsi +++ b/src/Compiler/Service/ServiceParsedInputOps.fsi @@ -37,7 +37,7 @@ type public PatternContext = | UnionCaseFieldIdentifier of referencedFields: string list * caseIdRange: range /// Completing a record field identifier in a pattern (e.g. fun { Field1 = a; Fie| } -> ) - | RecordFieldIdentifier of referencedFields: Ident list + | RecordFieldIdentifier of referencedFields: (string * range) list /// Any other position in a pattern that does not need special handling | Other From e43900dd3da9eb94d87df7565e4b4d15a6fe6cbb Mon Sep 17 00:00:00 2001 From: kerams Date: Wed, 30 Aug 2023 20:51:50 +0200 Subject: [PATCH 3/4] . --- src/Compiler/Service/FSharpCheckerResults.fs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index a47b093702..33840d6c43 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -1135,7 +1135,10 @@ type internal TypeCheckInfo | Item.RecdField info when equals cnr.Range fieldRange -> info.TyconRef.AllFieldAsRefList |> List.choose (fun field -> - if referencedFields |> List.exists (fun (fieldName, _) -> fieldName = field.DisplayName) then + if + referencedFields + |> List.exists (fun (fieldName, _) -> fieldName = field.DisplayName) + then None else FreshenRecdFieldRef ncenv field.Range field |> Item.RecdField |> Some) From 3f451ba12f3516b8080f1f0a7c6a62f2307cfd78 Mon Sep 17 00:00:00 2001 From: kerams Date: Wed, 30 Aug 2023 23:18:35 +0200 Subject: [PATCH 4/4] Surface area --- ...rp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl | 7 +++++++ ....Compiler.Service.SurfaceArea.netstandard20.release.bsl | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index 92ea2574c7..a229947008 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -3583,9 +3583,12 @@ FSharp.Compiler.EditorServices.PatternContext+PositionalUnionCaseField: FSharp.C FSharp.Compiler.EditorServices.PatternContext+PositionalUnionCaseField: FSharp.Compiler.Text.Range get_caseIdRange() FSharp.Compiler.EditorServices.PatternContext+PositionalUnionCaseField: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] fieldIndex FSharp.Compiler.EditorServices.PatternContext+PositionalUnionCaseField: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] get_fieldIndex() +FSharp.Compiler.EditorServices.PatternContext+RecordFieldIdentifier: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,FSharp.Compiler.Text.Range]] get_referencedFields() +FSharp.Compiler.EditorServices.PatternContext+RecordFieldIdentifier: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,FSharp.Compiler.Text.Range]] referencedFields FSharp.Compiler.EditorServices.PatternContext+Tags: Int32 NamedUnionCaseField FSharp.Compiler.EditorServices.PatternContext+Tags: Int32 Other FSharp.Compiler.EditorServices.PatternContext+Tags: Int32 PositionalUnionCaseField +FSharp.Compiler.EditorServices.PatternContext+Tags: Int32 RecordFieldIdentifier FSharp.Compiler.EditorServices.PatternContext+Tags: Int32 UnionCaseFieldIdentifier FSharp.Compiler.EditorServices.PatternContext+UnionCaseFieldIdentifier: FSharp.Compiler.Text.Range caseIdRange FSharp.Compiler.EditorServices.PatternContext+UnionCaseFieldIdentifier: FSharp.Compiler.Text.Range get_caseIdRange() @@ -3597,18 +3600,22 @@ FSharp.Compiler.EditorServices.PatternContext: Boolean Equals(System.Object, Sys FSharp.Compiler.EditorServices.PatternContext: Boolean IsNamedUnionCaseField FSharp.Compiler.EditorServices.PatternContext: Boolean IsOther FSharp.Compiler.EditorServices.PatternContext: Boolean IsPositionalUnionCaseField +FSharp.Compiler.EditorServices.PatternContext: Boolean IsRecordFieldIdentifier FSharp.Compiler.EditorServices.PatternContext: Boolean IsUnionCaseFieldIdentifier FSharp.Compiler.EditorServices.PatternContext: Boolean get_IsNamedUnionCaseField() FSharp.Compiler.EditorServices.PatternContext: Boolean get_IsOther() FSharp.Compiler.EditorServices.PatternContext: Boolean get_IsPositionalUnionCaseField() +FSharp.Compiler.EditorServices.PatternContext: Boolean get_IsRecordFieldIdentifier() FSharp.Compiler.EditorServices.PatternContext: Boolean get_IsUnionCaseFieldIdentifier() FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext NewNamedUnionCaseField(System.String, FSharp.Compiler.Text.Range) FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext NewPositionalUnionCaseField(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Boolean, FSharp.Compiler.Text.Range) +FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext NewRecordFieldIdentifier(Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,FSharp.Compiler.Text.Range]]) FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext NewUnionCaseFieldIdentifier(Microsoft.FSharp.Collections.FSharpList`1[System.String], FSharp.Compiler.Text.Range) FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext Other FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext get_Other() FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext+NamedUnionCaseField FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext+PositionalUnionCaseField +FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext+RecordFieldIdentifier FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext+Tags FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext+UnionCaseFieldIdentifier FSharp.Compiler.EditorServices.PatternContext: Int32 GetHashCode() diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl index 92ea2574c7..a229947008 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -3583,9 +3583,12 @@ FSharp.Compiler.EditorServices.PatternContext+PositionalUnionCaseField: FSharp.C FSharp.Compiler.EditorServices.PatternContext+PositionalUnionCaseField: FSharp.Compiler.Text.Range get_caseIdRange() FSharp.Compiler.EditorServices.PatternContext+PositionalUnionCaseField: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] fieldIndex FSharp.Compiler.EditorServices.PatternContext+PositionalUnionCaseField: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] get_fieldIndex() +FSharp.Compiler.EditorServices.PatternContext+RecordFieldIdentifier: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,FSharp.Compiler.Text.Range]] get_referencedFields() +FSharp.Compiler.EditorServices.PatternContext+RecordFieldIdentifier: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,FSharp.Compiler.Text.Range]] referencedFields FSharp.Compiler.EditorServices.PatternContext+Tags: Int32 NamedUnionCaseField FSharp.Compiler.EditorServices.PatternContext+Tags: Int32 Other FSharp.Compiler.EditorServices.PatternContext+Tags: Int32 PositionalUnionCaseField +FSharp.Compiler.EditorServices.PatternContext+Tags: Int32 RecordFieldIdentifier FSharp.Compiler.EditorServices.PatternContext+Tags: Int32 UnionCaseFieldIdentifier FSharp.Compiler.EditorServices.PatternContext+UnionCaseFieldIdentifier: FSharp.Compiler.Text.Range caseIdRange FSharp.Compiler.EditorServices.PatternContext+UnionCaseFieldIdentifier: FSharp.Compiler.Text.Range get_caseIdRange() @@ -3597,18 +3600,22 @@ FSharp.Compiler.EditorServices.PatternContext: Boolean Equals(System.Object, Sys FSharp.Compiler.EditorServices.PatternContext: Boolean IsNamedUnionCaseField FSharp.Compiler.EditorServices.PatternContext: Boolean IsOther FSharp.Compiler.EditorServices.PatternContext: Boolean IsPositionalUnionCaseField +FSharp.Compiler.EditorServices.PatternContext: Boolean IsRecordFieldIdentifier FSharp.Compiler.EditorServices.PatternContext: Boolean IsUnionCaseFieldIdentifier FSharp.Compiler.EditorServices.PatternContext: Boolean get_IsNamedUnionCaseField() FSharp.Compiler.EditorServices.PatternContext: Boolean get_IsOther() FSharp.Compiler.EditorServices.PatternContext: Boolean get_IsPositionalUnionCaseField() +FSharp.Compiler.EditorServices.PatternContext: Boolean get_IsRecordFieldIdentifier() FSharp.Compiler.EditorServices.PatternContext: Boolean get_IsUnionCaseFieldIdentifier() FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext NewNamedUnionCaseField(System.String, FSharp.Compiler.Text.Range) FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext NewPositionalUnionCaseField(Microsoft.FSharp.Core.FSharpOption`1[System.Int32], Boolean, FSharp.Compiler.Text.Range) +FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext NewRecordFieldIdentifier(Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,FSharp.Compiler.Text.Range]]) FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext NewUnionCaseFieldIdentifier(Microsoft.FSharp.Collections.FSharpList`1[System.String], FSharp.Compiler.Text.Range) FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext Other FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext get_Other() FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext+NamedUnionCaseField FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext+PositionalUnionCaseField +FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext+RecordFieldIdentifier FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext+Tags FSharp.Compiler.EditorServices.PatternContext: FSharp.Compiler.EditorServices.PatternContext+UnionCaseFieldIdentifier FSharp.Compiler.EditorServices.PatternContext: Int32 GetHashCode()