diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 7bf3e5ee399..c52fb1cf8aa 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -1812,8 +1812,6 @@ let BuildFieldMap (cenv: cenv) env isPartial ty (flds: ((Ident list * Ident) * ' let g = cenv.g let ad = env.eAccessRights - if isNil flds then invalidArg "flds" "BuildFieldMap" - let allFields = flds |> List.map (fun ((_, ident), _) -> ident) if allFields.Length > 1 then // In the case of nested record fields on the same level in record copy-and-update. diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index 73c2a36b5bd..9a94a3626b0 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -1313,7 +1313,7 @@ module ParsedInput = | _ -> pats |> List.tryPick (fun pat -> TryGetCompletionContextInPattern false pat None pos) - | SynPat.Record (fieldPats = pats) -> + | SynPat.Record (fieldPats = pats; range = m) when rangeContainsPos m pos -> pats |> List.tryPick (fun ((_, fieldId), _, pat) -> if rangeContainsPos fieldId.idRange pos then @@ -1328,15 +1328,16 @@ module ParsedInput = // That is, pos is after the last field and still within braces if pats - |> List.forall (fun (_, m, _) -> - match m with - | Some m -> rangeBeforePos m pos - | None -> false) + |> List.forall (fun (_, mEquals, pat) -> + match mEquals, pat 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) Some(CompletionContext.Pattern(PatternContext.RecordFieldIdentifier referencedFields)) else - None) + Some(CompletionContext.Pattern PatternContext.Other)) | SynPat.Ands (pats = pats) | SynPat.ArrayOrList (elementPats = pats) -> pats diff --git a/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs index 487bb0d3323..157331988df 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs @@ -1935,7 +1935,14 @@ type R1 = { A: int; B: int } type R2 = { C: int; D: int } match [] with -| [ { A = 2; l = 2 } ] +| [ { A = 2; l = 2 } ] -> () + +match { A = 1; B = 2 } with +| { A = 1; } -> () +| { A = 2; s } -> () +| { B = } -> () +| { X = ; A = 3 } -> () +| { } -> () """ VerifyCompletionList( @@ -1945,6 +1952,16 @@ match [] with [ "A"; "C"; "D"; "DU"; "X"; "log"; "let"; "Lazy" ] ) + VerifyCompletionList(fileContents, "| { A = 1; ", [ "B"; "R1"; "R2" ], [ "C"; "D" ]) + VerifyCompletionList(fileContents, "| { A = 2; s", [ "B"; "R1"; "R2" ], [ "C"; "D" ]) + VerifyCompletionList(fileContents, "| { B =", [ "R1"; "R2"; "Some"; "None"; "System"; "DU" ], [ "A"; "B"; "C"; "D" ]) + VerifyCompletionList(fileContents, "| { B = ", [ "R1"; "R2"; "Some"; "None"; "System"; "DU" ], [ "A"; "B"; "C"; "D" ]) + VerifyCompletionList(fileContents, "| { X =", [ "R1"; "R2"; "Some"; "None"; "System"; "DU" ], [ "A"; "B"; "C"; "D" ]) + VerifyCompletionList(fileContents, "| { X = ", [ "R1"; "R2"; "Some"; "None"; "System"; "DU" ], [ "A"; "B"; "C"; "D" ]) + + // Ideally C and D should not be present here, but right now we're not able to filter fields in an empty record pattern stub + VerifyCompletionList(fileContents, "| { ", [ "A"; "B"; "C"; "D"; "R1"; "R2" ], []) + [] 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`` ()