Skip to content

Commit

Permalink
filter pipe completions to only applicable functions
Browse files Browse the repository at this point in the history
  • Loading branch information
zth committed Nov 14, 2024
1 parent 06d2a92 commit 88a20bc
Show file tree
Hide file tree
Showing 12 changed files with 87 additions and 240 deletions.
49 changes: 21 additions & 28 deletions analysis/src/CompletionBackEnd.ml
Original file line number Diff line number Diff line change
Expand Up @@ -828,41 +828,31 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
if Debug.verbose () then print_endline "[ctx_path]--> CPString";
[
Completion.create "dummy" ~env
~kind:
(Completion.Value
(Ctype.newconstr (Path.Pident (Ident.create "string")) []));
~kind:(Completion.Value (Ctype.newconstr Predef.path_string []));
]
| CPBool ->
if Debug.verbose () then print_endline "[ctx_path]--> CPBool";
[
Completion.create "dummy" ~env
~kind:
(Completion.Value
(Ctype.newconstr (Path.Pident (Ident.create "bool")) []));
~kind:(Completion.Value (Ctype.newconstr Predef.path_bool []));
]
| CPInt ->
if Debug.verbose () then print_endline "[ctx_path]--> CPInt";
[
Completion.create "dummy" ~env
~kind:
(Completion.Value
(Ctype.newconstr (Path.Pident (Ident.create "int")) []));
~kind:(Completion.Value (Ctype.newconstr Predef.path_int []));
]
| CPFloat ->
if Debug.verbose () then print_endline "[ctx_path]--> CPFloat";
[
Completion.create "dummy" ~env
~kind:
(Completion.Value
(Ctype.newconstr (Path.Pident (Ident.create "float")) []));
~kind:(Completion.Value (Ctype.newconstr Predef.path_float []));
]
| CPArray None ->
if Debug.verbose () then print_endline "[ctx_path]--> CPArray (no payload)";
[
Completion.create "array" ~env
~kind:
(Completion.Value
(Ctype.newconstr (Path.Pident (Ident.create "array")) []));
~kind:(Completion.Value (Ctype.newconstr Predef.path_array []));
]
| CPArray (Some cp) -> (
if Debug.verbose () then
Expand All @@ -887,9 +877,7 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
what inner type it has. *)
[
Completion.create "dummy" ~env
~kind:
(Completion.Value
(Ctype.newconstr (Path.Pident (Ident.create "array")) []));
~kind:(Completion.Value (Ctype.newconstr Predef.path_array []));
])
| CPOption cp -> (
if Debug.verbose () then print_endline "[ctx_path]--> CPOption";
Expand Down Expand Up @@ -1135,6 +1123,10 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
(QueryEnv.toString env)
(QueryEnv.toString envFromCompletionItem)
else Printf.printf "CPPipe env:%s\n" (QueryEnv.toString env);
let tPath =
match typ with
| Builtin (_, t) | TypExpr t -> TypeUtils.pathFromTypeExpr t
in
let completionPath =
match typ with
| Builtin (builtin, _) ->
Expand Down Expand Up @@ -1186,13 +1178,15 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
completionsForPipeFromCompletionPath ~envCompletionIsMadeFrom ~opens
~pos ~scope ~debug ~prefix:funNamePrefix ~env ~rawOpens ~full
completionPath
|> TypeUtils.filterPipeableFunctions ~env ~full ?path:tPath
in
match completionPath with
| Some completionPath -> (
let completionsFromMainFn =
completionsForPipeFromCompletionPath ~envCompletionIsMadeFrom ~opens
~pos ~scope ~debug ~prefix:funNamePrefix ~env ~rawOpens ~full
completionPath
|> TypeUtils.filterPipeableFunctions ~env ~full ?path:tPath
in
let completions = completionsFromMainFn @ completionsFromExtraModule in
(* We add React element functions to the completion if we're in a JSX context *)
Expand Down Expand Up @@ -1822,8 +1816,7 @@ let rec completeTypedValue ?(typeArgContext : typeArgContext option) ~rawOpens
if prefix = "" then
[
create "\"\"" ~includesSnippets:true ~insertText:"\"$0\"" ~sortText:"A"
~kind:
(Value (Ctype.newconstr (Path.Pident (Ident.create "string")) []))
~kind:(Value (Ctype.newconstr Predef.path_string []))
~env;
]
else []
Expand Down Expand Up @@ -2012,7 +2005,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
stamp = -1;
fname = {loc = Location.none; txt = name};
optional = true;
typ = Ctype.newconstr (Path.Pident (Ident.create primitive)) [];
typ = Ctype.newconstr primitive [];
docstring = [];
deprecated = None;
}
Expand All @@ -2026,9 +2019,9 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
attributes = [];
fields =
[
mkField ~name:"version" ~primitive:"int";
mkField ~name:"module_" ~primitive:"string";
mkField ~name:"mode" ~primitive:"string";
mkField ~name:"version" ~primitive:Predef.path_int;
mkField ~name:"module_" ~primitive:Predef.path_string;
mkField ~name:"mode" ~primitive:Predef.path_string;
];
}
in
Expand All @@ -2044,7 +2037,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
stamp = -1;
fname = {loc = Location.none; txt = name};
optional = true;
typ = Ctype.newconstr (Path.Pident (Ident.create primitive)) [];
typ = Ctype.newconstr primitive [];
docstring = [];
deprecated = None;
}
Expand All @@ -2056,7 +2049,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
path = None;
attributes = [];
definition = `NameOnly "importAttributesConfig";
fields = [mkField ~name:"type_" ~primitive:"string"];
fields = [mkField ~name:"type_" ~primitive:Predef.path_string];
}
in
let rootConfig : completionType =
Expand All @@ -2068,8 +2061,8 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
definition = `NameOnly "moduleConfig";
fields =
[
mkField ~name:"from" ~primitive:"string";
mkField ~name:"with" ~primitive:"string";
mkField ~name:"from" ~primitive:Predef.path_string;
mkField ~name:"with" ~primitive:Predef.path_string;
];
}
in
Expand Down
32 changes: 21 additions & 11 deletions analysis/src/TypeUtils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1159,17 +1159,20 @@ let getExtraModuleToCompleteFromForType ~env ~full (t : Types.type_expr) =

(** Checks whether the provided type represents a function that takes the provided path
as the first argument (meaning it's pipeable). *)
let rec fnTakesType ~env ~full ~path t =
let rec fnTakesTypeAsFirstArg ~env ~full ~path t =
match t.Types.desc with
| Tlink t1
| Tsubst t1
| Tpoly (t1, [])
| Tconstr (Pident {name = "function$"}, [t1; _], _) ->
fnTakesType ~env ~full ~path t1
fnTakesTypeAsFirstArg ~env ~full ~path t1
| Tarrow _ -> (
match extractFunctionType ~env ~package:full.package t with
| (Nolabel, {desc = Tconstr (p, _, _)}) :: _, _ ->
Path.same p path || Path.name p = "t"
| (Nolabel, t) :: _, _ -> (
let p = pathFromTypeExpr t in
match p with
| None -> false
| Some p -> Path.same p path || Path.name p = "t")
| _ -> false)
| _ -> false

Expand All @@ -1189,13 +1192,20 @@ let transformCompletionToPipeCompletion ~env ~replaceRange
}

(** Filters out completions that are not pipeable from a list of completions. *)
let filterPipeableFunctions ~env ~full ~path ~replaceRange completions =
completions
|> List.filter_map (fun (completion : Completion.t) ->
match completion.kind with
| Value t when fnTakesType ~env ~full ~path t ->
transformCompletionToPipeCompletion ~env ~replaceRange completion
| _ -> None)
let filterPipeableFunctions ~env ~full ?path ?replaceRange completions =
match path with
| None -> completions
| Some path ->
completions
|> List.filter_map (fun (completion : Completion.t) ->
match completion.kind with
| Value t when fnTakesTypeAsFirstArg ~env ~full ~path t -> (
match replaceRange with
| None -> Some completion
| Some replaceRange ->
transformCompletionToPipeCompletion ~env ~replaceRange completion
)
| _ -> None)

let removeCurrentModuleIfNeeded ~envCompletionIsMadeFrom completionPath =
if
Expand Down
1 change: 1 addition & 0 deletions analysis/tests/src/CompletePrioritize1.res
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module Test = {
type t = {name: int}
let add = (a: float) => a +. 1.0
let name = t => t.name
}
let a: Test.t = {name: 4}
// a->
Expand Down
4 changes: 2 additions & 2 deletions analysis/tests/src/CompletionInferValues.res
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ let reactEventFn = (cb: ReactEvent.Mouse.t => unit) => {

@val external getSomeRecord: unit => someRecord = "getSomeRecord"

// let x = 123; let aliased = x; aliased->f
// let x = 123; let aliased = x; aliased->t
// ^com

// let x = getSomeRecord(); x.
Expand Down Expand Up @@ -166,4 +166,4 @@ let fn3 = (~cb: sameFileRecord => unit) => {
// Handles reusing the same name already in scope for bindings
let res = 1
// switch res { | res => res }
// ^hov
// ^hov
7 changes: 6 additions & 1 deletion analysis/tests/src/CompletionPipeSubmodules.res
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
module A = {
module B1 = {
type b1 = B1
type t = b1 // TODO(pipe-filter) Should be allowed without needing type t
let xx = B1
let d = (_: t) => ""
}
module B2 = {
let yy = 20
}
type t = {v: B1.b1}
type t = {v: B1.t} // TODO(pipe-filter) Should be allowed without needing type t
let x = {v: B1.B1}
}

Expand All @@ -20,11 +22,14 @@ module A = {

module C = {
type t = C
let do = (_: t) => ""
}

module D = {
module C2 = {
type t2 = C2
type t = t2 // TODO(pipe-filter) Should be allowed without needing type t
let do = (_: t) => ""
}

type d = {v: C.t, v2: C2.t2}
Expand Down
8 changes: 4 additions & 4 deletions analysis/tests/src/expected/CompletePrioritize1.res.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Complete src/CompletePrioritize1.res 5:6
posCursor:[5:6] posNoWhite:[5:5] Found expr:[5:3->0:-1]
Complete src/CompletePrioritize1.res 6:6
posCursor:[6:6] posNoWhite:[6:5] Found expr:[6:3->0:-1]
Completable: Cpath Value[a]->
Package opens Pervasives.JsxModules.place holder
Resolved opens 1 pervasives
Expand All @@ -11,10 +11,10 @@ CPPipe type path:Test.t
CPPipe pathFromEnv:Test found:true
Path Test.
[{
"label": "Test.add",
"label": "Test.name",
"kind": 12,
"tags": [],
"detail": "float => float",
"detail": "t => int",
"documentation": null
}]

24 changes: 0 additions & 24 deletions analysis/tests/src/expected/CompletionFromModule.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,6 @@ Path SomeOtherModule.
"tags": [],
"detail": "t => string",
"documentation": null
}, {
"label": "SomeOtherModule.getNName3",
"kind": 12,
"tags": [],
"detail": "irrelevantType => string",
"documentation": null
}, {
"label": "SomeOtherModule.thisShouldNotBeCompletedFor",
"kind": 12,
"tags": [],
"detail": "unit => string",
"documentation": null
}, {
"label": "SomeOtherModule.getNName2",
"kind": 12,
Expand Down Expand Up @@ -139,18 +127,6 @@ Path SomeOtherModule.
"tags": [],
"detail": "t => string",
"documentation": null
}, {
"label": "getNName3",
"kind": 12,
"tags": [],
"detail": "irrelevantType => string",
"documentation": null
}, {
"label": "thisShouldNotBeCompletedFor",
"kind": 12,
"tags": [],
"detail": "unit => string",
"documentation": null
}, {
"label": "getNName2",
"kind": 12,
Expand Down
24 changes: 0 additions & 24 deletions analysis/tests/src/expected/CompletionFromModule2.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,6 @@ Path CompletionFromModule.SomeOtherModule.
"tags": [],
"detail": "t => string",
"documentation": null
}, {
"label": "CompletionFromModule.SomeOtherModule.getNName3",
"kind": 12,
"tags": [],
"detail": "irrelevantType => string",
"documentation": null
}, {
"label": "CompletionFromModule.SomeOtherModule.thisShouldNotBeCompletedFor",
"kind": 12,
"tags": [],
"detail": "unit => string",
"documentation": null
}, {
"label": "CompletionFromModule.SomeOtherModule.getNName2",
"kind": 12,
Expand Down Expand Up @@ -113,18 +101,6 @@ Path CompletionFromModule.SomeOtherModule.
"tags": [],
"detail": "t => string",
"documentation": null
}, {
"label": "getNName3",
"kind": 12,
"tags": [],
"detail": "irrelevantType => string",
"documentation": null
}, {
"label": "thisShouldNotBeCompletedFor",
"kind": 12,
"tags": [],
"detail": "unit => string",
"documentation": null
}, {
"label": "getNName2",
"kind": 12,
Expand Down
Loading

0 comments on commit 88a20bc

Please sign in to comment.