diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index 711914d9489..89b7e38a764 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,15 @@ 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 +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 when rangeContainsPos m pos -> Some CompletionContext.Invalid + | 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 4131e9206cb..bfcb446a5b0 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/CompletionProviderTests.fs @@ -1674,6 +1674,22 @@ 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 =