From a4d2c1cbeb8fac1083b92b4743fcb9aed0872c79 Mon Sep 17 00:00:00 2001 From: kerams Date: Sat, 5 Aug 2023 12:11:53 +0200 Subject: [PATCH 1/2] Improve completions for union field patterns --- src/Compiler/Service/ServiceParsedInputOps.fs | 36 ++++++++++++++++--- .../CompletionProviderTests.fs | 15 ++++++++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index 711914d9489..4610eda26f4 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -1269,12 +1269,21 @@ module ParsedInput = else let context = Some(PatternContext.NamedUnionCaseField(patId.idText, id.Range)) TryGetCompletionContextInPattern suppressIdentifierCompletions pat context pos) - | SynPat.LongIdent (argPats = SynArgPats.Pats pats; longDotId = id) -> + | SynPat.LongIdent (argPats = SynArgPats.Pats pats; longDotId = id; range = m) when rangeContainsPos m pos -> match pats with - | [ SynPat.Named _ as pat ] -> - TryGetCompletionContextInPattern false pat (Some(PatternContext.PositionalUnionCaseField(None, id.Range))) pos + + // fun (Some v| ) -> + | [ SynPat.Named _ ] -> Some(CompletionContext.Pattern(PatternContext.PositionalUnionCaseField(None, id.Range))) + + // fun (Case (| )) -> + | [ SynPat.Paren (SynPat.Const (SynConst.Unit, _), m) ] when rangeContainsPos m pos -> + Some (CompletionContext.Pattern (PatternContext.PositionalUnionCaseField (Some 0, id.Range))) + + // fun (Case (a| , b)) -> | [ SynPat.Paren (SynPat.Tuple _ | SynPat.Named _ as pat, _) ] -> TryGetCompletionContextInPattern false pat (Some(PatternContext.PositionalUnionCaseField(Some 0, id.Range))) pos + |> Option.orElseWith (fun () -> Some CompletionContext.Invalid) + | _ -> pats |> List.tryPick (fun pat -> TryGetCompletionContextInPattern false pat None pos) @@ -1282,7 +1291,7 @@ module ParsedInput = | SynPat.ArrayOrList (elementPats = pats) -> pats |> List.tryPick (fun pat -> TryGetCompletionContextInPattern suppressIdentifierCompletions pat None pos) - | SynPat.Tuple (elementPats = pats) -> + | SynPat.Tuple (elementPats = pats; commaRanges = commas; range = m) -> pats |> List.indexed |> List.tryPick (fun (i, pat) -> @@ -1295,6 +1304,13 @@ module ParsedInput = None TryGetCompletionContextInPattern suppressIdentifierCompletions pat context pos) + |> Option.orElseWith (fun () -> + // Last resort - check for fun (Case (a, | )) -> + // That is, pos is after the last comma and before the end of the tuple + match previousContext, List.tryLast commas with + | Some (PatternContext.PositionalUnionCaseField (_, caseIdRange)), Some mComma when rangeBeforePos mComma pos && rangeContainsPos m pos -> + Some (CompletionContext.Pattern (PatternContext.PositionalUnionCaseField(Some (pats.Length - 1), caseIdRange))) + | _ -> None) | SynPat.Named (range = m) when rangeContainsPos m pos -> if suppressIdentifierCompletions then Some CompletionContext.Invalid @@ -1312,7 +1328,17 @@ module ParsedInput = TryGetCompletionContextInPattern suppressIdentifierCompletions pat1 None pos |> Option.orElseWith (fun () -> TryGetCompletionContextInPattern suppressIdentifierCompletions pat2 None pos) | SynPat.IsInst (_, m) when rangeContainsPos m pos -> Some CompletionContext.Type - | SynPat.Wild m when rangeContainsPos m pos -> Some CompletionContext.Invalid + | SynPat.Wild m -> + if rangeContainsPos m pos && m.StartColumn <> m.EndColumn then + // fun (Case (_| )) -> + Some CompletionContext.Invalid + //elif then + // // fun (Case (a, | )) -> + // // A synthetic SynPat.Wild with a 0-length range is inserted after a comma like this. + // // We return with the context from higher up, which should in this example be PositionalUnionCaseField (Some 1, ...). + // previousContext |> Option.map CompletionContext.Pattern + else + None | SynPat.Typed (pat = pat; targetType = synType) -> if rangeContainsPos pat.Range pos then TryGetCompletionContextInPattern suppressIdentifierCompletions pat previousContext pos diff --git a/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs index 4131e9206cb..79458feeda1 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs @@ -1674,6 +1674,21 @@ let x (du: Du list) = VerifyCompletionList(fileContents, "| [ C (first, rest); C (f", [ "option" ], [ "first" ]) VerifyCompletionList(fileContents, "| [ C (first, rest); C (f, l", [ "list" ], [ "rest" ]) + [] + let ``Completion list contains relevant items for the correct union case field pattern before its identifier has been typed`` () = + let fileContents = + """ +type Du = + | C of first: Du * second: Result + +let x du = + match du with + | C () -> () + | C (first, ) -> () +""" + VerifyCompletionList(fileContents, "| C (", [ "first"; "du" ], [ "second"; "result" ]) + VerifyCompletionList(fileContents, "| C (first, ", [ "second"; "result" ], [ "first"; "du" ]) + [] let ``Completion list contains suggested names for union case field pattern in a let binding, lambda and member`` () = let fileContents = From fd22b4530b387be77ee72ccd64cc8a6b875a391c Mon Sep 17 00:00:00 2001 From: kerams Date: Sat, 5 Aug 2023 12:22:16 +0200 Subject: [PATCH 2/2] . --- src/Compiler/Service/ServiceParsedInputOps.fs | 20 ++++++------------- .../CompletionProviderTests.fs | 1 + 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index 4610eda26f4..89b7e38a764 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -1277,7 +1277,7 @@ module ParsedInput = // fun (Case (| )) -> | [ SynPat.Paren (SynPat.Const (SynConst.Unit, _), m) ] when rangeContainsPos m pos -> - Some (CompletionContext.Pattern (PatternContext.PositionalUnionCaseField (Some 0, id.Range))) + Some(CompletionContext.Pattern(PatternContext.PositionalUnionCaseField(Some 0, id.Range))) // fun (Case (a| , b)) -> | [ SynPat.Paren (SynPat.Tuple _ | SynPat.Named _ as pat, _) ] -> @@ -1308,8 +1308,10 @@ module ParsedInput = // Last resort - check for fun (Case (a, | )) -> // That is, pos is after the last comma and before the end of the tuple match previousContext, List.tryLast commas with - | Some (PatternContext.PositionalUnionCaseField (_, caseIdRange)), Some mComma when rangeBeforePos mComma pos && rangeContainsPos m pos -> - Some (CompletionContext.Pattern (PatternContext.PositionalUnionCaseField(Some (pats.Length - 1), caseIdRange))) + | Some (PatternContext.PositionalUnionCaseField (_, caseIdRange)), Some mComma when + rangeBeforePos mComma pos && rangeContainsPos m pos + -> + Some(CompletionContext.Pattern(PatternContext.PositionalUnionCaseField(Some(pats.Length - 1), caseIdRange))) | _ -> None) | SynPat.Named (range = m) when rangeContainsPos m pos -> if suppressIdentifierCompletions then @@ -1328,17 +1330,7 @@ module ParsedInput = TryGetCompletionContextInPattern suppressIdentifierCompletions pat1 None pos |> Option.orElseWith (fun () -> TryGetCompletionContextInPattern suppressIdentifierCompletions pat2 None pos) | SynPat.IsInst (_, m) when rangeContainsPos m pos -> Some CompletionContext.Type - | SynPat.Wild m -> - if rangeContainsPos m pos && m.StartColumn <> m.EndColumn then - // fun (Case (_| )) -> - Some CompletionContext.Invalid - //elif then - // // fun (Case (a, | )) -> - // // A synthetic SynPat.Wild with a 0-length range is inserted after a comma like this. - // // We return with the context from higher up, which should in this example be PositionalUnionCaseField (Some 1, ...). - // previousContext |> Option.map CompletionContext.Pattern - else - None + | SynPat.Wild m when rangeContainsPos m pos && m.StartColumn <> m.EndColumn -> Some CompletionContext.Invalid | SynPat.Typed (pat = pat; targetType = synType) -> if rangeContainsPos pat.Range pos then TryGetCompletionContextInPattern suppressIdentifierCompletions pat previousContext pos diff --git a/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs index 79458feeda1..bfcb446a5b0 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs @@ -1686,6 +1686,7 @@ let x du = | C () -> () | C (first, ) -> () """ + VerifyCompletionList(fileContents, "| C (", [ "first"; "du" ], [ "second"; "result" ]) VerifyCompletionList(fileContents, "| C (first, ", [ "second"; "result" ], [ "first"; "du" ])