@@ -49,11 +49,6 @@ open FSharp.Compiler.Text.Range
49
49
open FSharp.Compiler .TypedTree
50
50
open FSharp.Compiler .TypedTreeBasics
51
51
open FSharp.Compiler .TypedTreeOps
52
- open FSharp.Compiler .AbstractIL
53
- open System.Reflection .PortableExecutable
54
- open FSharp.Compiler .CreateILModule
55
- open FSharp.Compiler .IlxGen
56
- open FSharp.Compiler .BuildGraph
57
52
58
53
open Internal.Utilities
59
54
open Internal.Utilities .Collections
@@ -934,6 +929,85 @@ type internal TypeCheckInfo
934
929
935
930
let DefaultCompletionItem item = CompletionItem ValueNone ValueNone item
936
931
932
+ let CompletionItemSuggestedName displayName =
933
+ {
934
+ ItemWithInst = ItemWithNoInst( Item.NewDef( Ident( displayName, range0)))
935
+ MinorPriority = 0
936
+ Type = None
937
+ Kind = CompletionItemKind.SuggestedName
938
+ IsOwnMember = false
939
+ Unresolved = None
940
+ }
941
+
942
+ /// Checks whether the suggested name is unused.
943
+ /// In the future we could use an increasing numeric suffix for conflict resolution
944
+ let CreateCompletionItemForSuggestedPatternName ( pos : pos ) name =
945
+ if String.IsNullOrWhiteSpace name then
946
+ None
947
+ else
948
+ let name = String.lowerCaseFirstChar name
949
+
950
+ let unused =
951
+ sResolutions.CapturedNameResolutions
952
+ |> ResizeArray.forall ( fun r ->
953
+ match r.Item with
954
+ | Item.Value vref when r.Pos.Line = pos.Line -> vref.DisplayName <> name
955
+ | _ -> true )
956
+
957
+ if unused then
958
+ Some( CompletionItemSuggestedName name)
959
+ else
960
+ None
961
+
962
+ /// Suggest name based on type
963
+ let SuggestNameBasedOnType g pos ty =
964
+ if isNumericType g ty then
965
+ CreateCompletionItemForSuggestedPatternName pos " num"
966
+ else
967
+ match tryTcrefOfAppTy g ty with
968
+ | ValueSome tcref when not ( tyconRefEq g g.system_ Object_ tcref tcref) ->
969
+ CreateCompletionItemForSuggestedPatternName pos tcref.DisplayName
970
+ | _ -> None
971
+
972
+ /// Suggest names based on field name and type, add them to the list
973
+ let SuggestNameForUnionCaseFieldPattern g caseIdPos fieldPatternPos ( uci : UnionCaseInfo ) indexOrName completions =
974
+ let field =
975
+ match indexOrName with
976
+ | Choice1Of2 index ->
977
+ // Index is None when parentheses were not used, i.e. "| Some v ->" - suggest a name only when the case has a single field
978
+ match uci.UnionCase.RecdFieldsArray, index with
979
+ | [| field |], None -> Some field
980
+ | [| _ |], Some _
981
+ | _, None -> None
982
+ | arr, Some index -> arr |> Array.tryItem index
983
+ | Choice2Of2 name -> uci.UnionCase.RecdFieldsArray |> Array.tryFind ( fun x -> x.DisplayName = name)
984
+
985
+ field
986
+ |> Option.map ( fun field ->
987
+ let ty =
988
+ // If the field type is generic, suggest a name based on the solution
989
+ if isTyparTy g field.FormalType then
990
+ sResolutions.CapturedNameResolutions
991
+ |> ResizeArray.tryPick ( fun r ->
992
+ match r.Item with
993
+ | Item.Value vref when r.Pos = fieldPatternPos -> Some( stripTyparEqns vref.Type)
994
+ | _ -> None)
995
+ |> Option.defaultValue field.FormalType
996
+ else
997
+ field.FormalType
998
+
999
+ let fieldName =
1000
+ // If the field has not been given an explicit name, do not suggest the generated one
1001
+ if field.rfield_ name_ generated then
1002
+ " "
1003
+ else
1004
+ field.DisplayName
1005
+
1006
+ completions
1007
+ |> List.prependIfSome ( SuggestNameBasedOnType g caseIdPos ty)
1008
+ |> List.prependIfSome ( CreateCompletionItemForSuggestedPatternName caseIdPos fieldName))
1009
+ |> Option.defaultValue completions
1010
+
937
1011
let getItem ( x : ItemWithInst ) = x.Item
938
1012
939
1013
let GetDeclaredItems
@@ -1182,10 +1256,10 @@ type internal TypeCheckInfo
1182
1256
| atStart when atStart = 0 -> 0
1183
1257
| otherwise -> otherwise - 1
1184
1258
1259
+ let pos = mkPos line colAtEndOfNamesAndResidue
1260
+
1185
1261
// Look for a "special" completion context
1186
1262
let completionContext =
1187
- let pos = mkPos line colAtEndOfNamesAndResidue
1188
-
1189
1263
// If the completion context we have computed higher up the stack is for the same position,
1190
1264
// reuse it, otherwise recompute
1191
1265
match completionContextAtPos with
@@ -1400,7 +1474,7 @@ type internal TypeCheckInfo
1400
1474
m)
1401
1475
1402
1476
// Completion at '(x: ...)"
1403
- | Some CompletionContext.PatternType
1477
+ | Some CompletionContext.Type
1404
1478
// Completion at '| Case1 of ...'
1405
1479
| Some CompletionContext.UnionCaseFieldsDeclaration
1406
1480
// Completion at 'type Long = int6...' or 'type SomeUnion = Abc...'
@@ -1434,6 +1508,51 @@ type internal TypeCheckInfo
1434
1508
denv,
1435
1509
m)
1436
1510
1511
+ | Some ( CompletionContext.Pattern patternContext) ->
1512
+ let declaredItems =
1513
+ GetDeclaredItems(
1514
+ parseResultsOpt,
1515
+ lineStr,
1516
+ origLongIdentOpt,
1517
+ colAtEndOfNamesAndResidue,
1518
+ residueOpt,
1519
+ lastDotPos,
1520
+ line,
1521
+ loc,
1522
+ filterCtors,
1523
+ resolveOverloads,
1524
+ false ,
1525
+ getAllSymbols
1526
+ )
1527
+ |> Option.map ( fun ( items , denv , range ) ->
1528
+ let filtered =
1529
+ items
1530
+ |> List.filter ( fun item ->
1531
+ match item.Item with
1532
+ | Item.Value v -> v.LiteralValue.IsSome
1533
+ | _ -> true )
1534
+
1535
+ filtered, denv, range)
1536
+
1537
+ let indexOrName , caseIdRange =
1538
+ match patternContext with
1539
+ | PatternContext.PositionalUnionCaseField ( index, m) -> Choice1Of2 index, m
1540
+ | PatternContext.NamedUnionCaseField ( name, m) -> Choice2Of2 name, m
1541
+ | PatternContext.Other -> Choice1Of2 None, range0
1542
+
1543
+ // No special handling for PatternContext.Other other than filtering out non-literal values
1544
+ if equals caseIdRange range0 then
1545
+ declaredItems
1546
+ else
1547
+ GetCapturedNameResolutions caseIdRange.End ResolveOverloads.Yes
1548
+ |> ResizeArray.tryPick ( fun r ->
1549
+ match r.Item with
1550
+ | Item.UnionCase ( uci, _) ->
1551
+ let list = declaredItems |> Option.map p13 |> Option.defaultValue []
1552
+ Some( SuggestNameForUnionCaseFieldPattern g caseIdRange.End pos uci indexOrName list, r.DisplayEnv, r.Range)
1553
+ | _ -> None)
1554
+ |> Option.orElse declaredItems
1555
+
1437
1556
// Other completions
1438
1557
| cc ->
1439
1558
match residueOpt |> Option.bind Seq.tryHead with
0 commit comments