Skip to content

Commit 6d198cc

Browse files
zthcristianoc
authored andcommitted
start work on following pattern path
1 parent bbb52dd commit 6d198cc

File tree

5 files changed

+215
-44
lines changed

5 files changed

+215
-44
lines changed

analysis/src/CompletionBackEnd.ml

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,7 @@ and getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
715715
(* Pipe completion with array just needs to know that it's an array, not
716716
what inner type it has. *)
717717
[
718-
Completion.create "array" ~env
718+
Completion.create "dummy" ~env
719719
~kind:
720720
(Completion.Value
721721
(Ctype.newconstr (Path.Pident (Ident.create "array")) []));
@@ -738,6 +738,7 @@ and getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
738738
|> getCompletionsForPath ~package ~opens ~allFiles ~pos ~exact
739739
~completionContext ~env ~scope
740740
| CPApply (cp, labels) -> (
741+
(* TODO: Also needs to support ExtractedType *)
741742
match
742743
cp
743744
|> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
@@ -822,6 +823,7 @@ and getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
822823
~kind:(Completion.Field (field, recordAsString)))
823824
else None))
824825
| CPObj (cp, label) -> (
826+
(* TODO: Also needs to support ExtractedType *)
825827
match
826828
cp
827829
|> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
@@ -1048,6 +1050,7 @@ and getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
10481050
~kind:(Completion.Value (Utils.unwrapIfOption typ));
10491051
])
10501052
| CArgument {functionContextPath; argumentLabel} -> (
1053+
(* TODO: Also needs to support ExtractedType *)
10511054
let labels, env =
10521055
match
10531056
functionContextPath
@@ -1084,6 +1087,31 @@ and getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
10841087
(Completion.Value
10851088
(if expandOption then Utils.unwrapIfOption typ else typ));
10861089
])
1090+
| CPatternPath {rootCtxPath; nested} -> (
1091+
match
1092+
rootCtxPath
1093+
|> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
1094+
~exact:true ~scope
1095+
|> completionsGetCompletionType2 ~full ~opens ~rawOpens ~allFiles ~pos
1096+
~scope
1097+
with
1098+
| Some (typ, env) -> (
1099+
let typ =
1100+
match typ with
1101+
| ExtractedType typ -> Some typ
1102+
| TypeExpr typ -> typ |> TypeUtils.extractType ~env ~package
1103+
in
1104+
match typ with
1105+
| None -> []
1106+
| Some typ -> (
1107+
match typ |> TypeUtils.resolveNested ~env ~full ~nested with
1108+
| Some (typ, env, _completionContext) ->
1109+
[
1110+
Completion.create "dummy" ~env
1111+
~kind:(Completion.ExtractedType (typ, `Value));
1112+
]
1113+
| None -> []))
1114+
| None -> [])
10871115

10881116
let getOpens ~debug ~rawOpens ~package ~env =
10891117
if debug && rawOpens <> [] then

analysis/src/CompletionFrontEnd.ml

Lines changed: 86 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -292,39 +292,105 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text =
292292
scope :=
293293
!scope |> Scope.addValue ~name:vd.pval_name.txt ~loc:vd.pval_name.loc
294294
in
295-
let rec scopePattern ?contextPath (pat : Parsetree.pattern) =
295+
let rec scopePattern ?contextPath
296+
?(patternPath : Completable.nestedPath list = [])
297+
(pat : Parsetree.pattern) =
298+
let contextPathToSave =
299+
match (contextPath, patternPath) with
300+
| maybeContextPath, [] -> maybeContextPath
301+
| Some contextPath, patternPath ->
302+
Some
303+
(Completable.CPatternPath
304+
{rootCtxPath = contextPath; nested = List.rev patternPath})
305+
| _ -> None
306+
in
296307
match pat.ppat_desc with
297308
| Ppat_any -> ()
298309
| Ppat_var {txt; loc} ->
299-
scope := !scope |> Scope.addValue ~name:txt ~loc ?contextPath
310+
scope :=
311+
!scope |> Scope.addValue ~name:txt ~loc ?contextPath:contextPathToSave
300312
| Ppat_alias (p, asA) ->
301-
scopePattern p;
313+
scopePattern p ~patternPath ?contextPath;
314+
let ctxPath =
315+
if contextPathToSave = None then
316+
match p with
317+
| {ppat_desc = Ppat_var {txt}} ->
318+
Some (Completable.CPId ([txt], Value))
319+
| _ -> None
320+
else None
321+
in
302322
scope :=
303-
!scope
304-
|> Scope.addValue ~name:asA.txt ~loc:asA.loc
305-
?contextPath:
306-
(match p with
307-
| {ppat_desc = Ppat_var {txt}} -> Some (CPId ([txt], Value))
308-
| _ -> None)
323+
!scope |> Scope.addValue ~name:asA.txt ~loc:asA.loc ?contextPath:ctxPath
309324
| Ppat_constant _ | Ppat_interval _ -> ()
310-
| Ppat_tuple pl -> pl |> List.iter (scopePattern ?contextPath)
325+
| Ppat_tuple pl ->
326+
pl
327+
|> List.iteri (fun index p ->
328+
scopePattern p
329+
~patternPath:(NTupleItem {itemNum = index} :: patternPath)
330+
?contextPath)
311331
| Ppat_construct (_, None) -> ()
312-
| Ppat_construct (_, Some p) -> scopePattern ?contextPath p
332+
| Ppat_construct ({txt}, Some {ppat_desc = Ppat_tuple pl}) ->
333+
pl
334+
|> List.iteri (fun index p ->
335+
scopePattern p
336+
~patternPath:
337+
(NVariantPayload
338+
{
339+
itemNum = index;
340+
constructorName = Utils.getUnqualifiedName txt;
341+
}
342+
:: patternPath)
343+
?contextPath)
344+
| Ppat_construct ({txt}, Some p) ->
345+
scopePattern
346+
~patternPath:
347+
(NVariantPayload
348+
{itemNum = 0; constructorName = Utils.getUnqualifiedName txt}
349+
:: patternPath)
350+
?contextPath p
313351
| Ppat_variant (_, None) -> ()
314-
| Ppat_variant (_, Some p) -> scopePattern ?contextPath p
352+
| Ppat_variant (txt, Some {ppat_desc = Ppat_tuple pl}) ->
353+
pl
354+
|> List.iteri (fun index p ->
355+
scopePattern p
356+
~patternPath:
357+
(NPolyvariantPayload {itemNum = index; constructorName = txt}
358+
:: patternPath)
359+
?contextPath)
360+
| Ppat_variant (txt, Some p) ->
361+
scopePattern
362+
~patternPath:
363+
(NPolyvariantPayload {itemNum = 0; constructorName = txt}
364+
:: patternPath)
365+
?contextPath p
315366
| Ppat_record (fields, _) ->
316-
fields |> List.iter (fun (_, p) -> scopePattern ?contextPath p)
317-
| Ppat_array pl -> pl |> List.iter (scopePattern ?contextPath)
318-
| Ppat_or (p1, _) -> scopePattern ?contextPath p1
367+
fields
368+
|> List.iter (fun (fname, p) ->
369+
match fname with
370+
| {Location.txt = Longident.Lident fname} ->
371+
scopePattern
372+
~patternPath:
373+
(Completable.NFollowRecordField {fieldName = fname}
374+
:: patternPath)
375+
?contextPath p
376+
| _ -> ())
377+
| Ppat_array pl ->
378+
pl
379+
|> List.iter
380+
(scopePattern ~patternPath:(NArray :: patternPath) ?contextPath)
381+
| Ppat_or (p1, _) -> scopePattern ~patternPath ?contextPath p1
319382
| Ppat_constraint (p, coreType) ->
320-
scopePattern ?contextPath:(TypeUtils.contextPathFromCoreType coreType) p
383+
scopePattern ~patternPath
384+
?contextPath:(TypeUtils.contextPathFromCoreType coreType)
385+
p
321386
| Ppat_type _ -> ()
322-
| Ppat_lazy p -> scopePattern ?contextPath p
387+
| Ppat_lazy p -> scopePattern ~patternPath ?contextPath p
323388
| Ppat_unpack {txt; loc} ->
324-
scope := !scope |> Scope.addValue ~name:txt ~loc ?contextPath
325-
| Ppat_exception p -> scopePattern ?contextPath p
389+
scope :=
390+
!scope |> Scope.addValue ~name:txt ~loc ?contextPath:contextPathToSave
391+
| Ppat_exception p -> scopePattern ~patternPath ?contextPath p
326392
| Ppat_extension _ -> ()
327-
| Ppat_open (_, p) -> scopePattern ?contextPath p
393+
| Ppat_open (_, p) -> scopePattern ~patternPath ?contextPath p
328394
in
329395

330396
let lookingForPat = ref None in

analysis/src/SharedTypes.ml

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,29 @@ module Completable = struct
520520
| Labelled of string
521521
| Optional of string
522522

523+
(** Additional context for nested completion where needed. *)
524+
type nestedContext = RecordField of {seenFields: string list}
525+
526+
type nestedPath =
527+
| NTupleItem of {itemNum: int}
528+
| NFollowRecordField of {fieldName: string}
529+
| NRecordBody of {seenFields: string list}
530+
| NVariantPayload of {constructorName: string; itemNum: int}
531+
| NPolyvariantPayload of {constructorName: string; itemNum: int}
532+
| NArray
533+
534+
let nestedPathToString p =
535+
match p with
536+
| NTupleItem {itemNum} -> "tuple($" ^ string_of_int itemNum ^ ")"
537+
| NFollowRecordField {fieldName} -> "recordField(" ^ fieldName ^ ")"
538+
| NRecordBody _ -> "recordBody"
539+
| NVariantPayload {constructorName; itemNum} ->
540+
"variantPayload::" ^ constructorName ^ "($" ^ string_of_int itemNum ^ ")"
541+
| NPolyvariantPayload {constructorName; itemNum} ->
542+
"polyvariantPayload::" ^ constructorName ^ "($" ^ string_of_int itemNum
543+
^ ")"
544+
| NArray -> "array"
545+
523546
type contextPath =
524547
| CPString
525548
| CPArray of contextPath option
@@ -544,29 +567,7 @@ module Completable = struct
544567
argumentLabel: argumentLabel;
545568
}
546569
| CJsxPropValue of {pathToComponent: string list; propName: string}
547-
548-
(** Additional context for nested completion where needed. *)
549-
type nestedContext = RecordField of {seenFields: string list}
550-
551-
type nestedPath =
552-
| NTupleItem of {itemNum: int}
553-
| NFollowRecordField of {fieldName: string}
554-
| NRecordBody of {seenFields: string list}
555-
| NVariantPayload of {constructorName: string; itemNum: int}
556-
| NPolyvariantPayload of {constructorName: string; itemNum: int}
557-
| NArray
558-
559-
let nestedPathToString p =
560-
match p with
561-
| NTupleItem {itemNum} -> "tuple($" ^ string_of_int itemNum ^ ")"
562-
| NFollowRecordField {fieldName} -> "recordField(" ^ fieldName ^ ")"
563-
| NRecordBody _ -> "recordBody"
564-
| NVariantPayload {constructorName; itemNum} ->
565-
"variantPayload::" ^ constructorName ^ "($" ^ string_of_int itemNum ^ ")"
566-
| NPolyvariantPayload {constructorName; itemNum} ->
567-
"polyvariantPayload::" ^ constructorName ^ "($" ^ string_of_int itemNum
568-
^ ")"
569-
| NArray -> "array"
570+
| CPatternPath of {rootCtxPath: contextPath; nested: nestedPath list}
570571

571572
type patternMode = Default | Destructuring
572573

@@ -639,6 +640,13 @@ module Completable = struct
639640
^ ")"
640641
| CJsxPropValue {pathToComponent; propName} ->
641642
"CJsxPropValue " ^ (pathToComponent |> list) ^ " " ^ propName
643+
| CPatternPath {rootCtxPath; nested} ->
644+
"CPatternPath("
645+
^ contextPathToString rootCtxPath
646+
^ ")" ^ "->"
647+
^ (nested
648+
|> List.map (fun nestedPath -> nestedPathToString nestedPath)
649+
|> String.concat "->")
642650

643651
let toString = function
644652
| Cpath cp -> "Cpath " ^ contextPathToString cp

analysis/tests/src/CompletionInferValues.res

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,24 @@ module Div = {
5757

5858
// let x: someRecord = {name: "Hello", age: 123}; x.
5959
// ^com
60+
61+
type someVariant = One | Two | Three(int, string)
62+
type someNestedRecord = {someRecord: someRecord}
63+
64+
type someRecordWithNestedStuff = {
65+
things: string,
66+
srecord: someRecord,
67+
nested: someNestedRecord,
68+
someStuff: bool,
69+
}
70+
71+
type otherNestedRecord = {someRecord: someRecord, someTuple: (someVariant, int)}
72+
73+
// let x: someRecordWithNestedStuff = {things: "", someRecord: {name: "Hello", age: 123}, someStuff: true}; let {srecord} = x; srecord.
74+
// ^com
75+
76+
// let x: someRecordWithNestedStuff = {things: "", someRecord: {name: "Hello", age: 123}, someStuff: true}; let {nested: aliased} = x; aliased.
77+
// ^com
78+
79+
// let x: someRecordWithNestedStuff = {things: "", someRecord: {name: "Hello", age: 123}, someStuff: true}; let {srecord, nested: {someRecord}} = x; someRecord.
80+
// ^com

analysis/tests/src/expected/CompletionInferValues.res.txt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,51 @@ Completable: Cpath Value[x].""
220220
"documentation": null
221221
}]
222222

223+
Complete src/CompletionInferValues.res 72:135
224+
posCursor:[72:135] posNoWhite:[72:134] Found expr:[72:127->72:135]
225+
Pexp_field [72:127->72:134] _:[81:0->72:135]
226+
Completable: Cpath Value[srecord].""
227+
[{
228+
"label": "name",
229+
"kind": 5,
230+
"tags": [],
231+
"detail": "name: string\n\nsomeRecord",
232+
"documentation": null
233+
}, {
234+
"label": "age",
235+
"kind": 5,
236+
"tags": [],
237+
"detail": "age: int\n\nsomeRecord",
238+
"documentation": null
239+
}]
240+
241+
Complete src/CompletionInferValues.res 75:143
242+
posCursor:[75:143] posNoWhite:[75:142] Found expr:[75:135->75:143]
243+
Pexp_field [75:135->75:142] _:[81:0->75:143]
244+
Completable: Cpath Value[aliased].""
245+
[{
246+
"label": "someRecord",
247+
"kind": 5,
248+
"tags": [],
249+
"detail": "someRecord: someRecord\n\nsomeNestedRecord",
250+
"documentation": null
251+
}]
252+
253+
Complete src/CompletionInferValues.res 78:160
254+
posCursor:[78:160] posNoWhite:[78:159] Found expr:[78:149->78:160]
255+
Pexp_field [78:149->78:159] _:[81:0->78:160]
256+
Completable: Cpath Value[someRecord].""
257+
[{
258+
"label": "name",
259+
"kind": 5,
260+
"tags": [],
261+
"detail": "name: string\n\nsomeRecord",
262+
"documentation": null
263+
}, {
264+
"label": "age",
265+
"kind": 5,
266+
"tags": [],
267+
"detail": "age: int\n\nsomeRecord",
268+
"documentation": null
269+
}]
270+

0 commit comments

Comments
 (0)