Skip to content

Commit 05a1393

Browse files
authored
Pipe completion unknown/type parameter return types (#662)
1 parent ba532ac commit 05a1393

8 files changed

+84
-29
lines changed

analysis/src/Commands.ml

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ let getCompletions ~debug ~path ~pos ~currentFile ~forHover =
1515
(* Only perform expensive ast operations if there are completables *)
1616
match Cmt.loadFullCmtFromPath ~path with
1717
| None -> []
18-
| Some {file; package} ->
19-
let env = SharedTypes.QueryEnv.fromFile file in
18+
| Some full ->
19+
let env = SharedTypes.QueryEnv.fromFile full.file in
2020
completable
21-
|> CompletionBackEnd.processCompletable ~debug ~package ~pos ~scope ~env
21+
|> CompletionBackEnd.processCompletable ~debug ~full ~pos ~scope ~env
2222
~forHover))
2323

2424
let completion ~debug ~path ~pos ~currentFile =

analysis/src/CompletionBackEnd.ml

+39-15
Original file line numberDiff line numberDiff line change
@@ -1157,8 +1157,17 @@ let completionsGetTypeEnv = function
11571157
| {Completion.kind = Field ({typ}, _); env} :: _ -> Some (typ, env)
11581158
| _ -> None
11591159

1160-
let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
1161-
~env ~exact ~scope (contextPath : Completable.contextPath) =
1160+
let findReturnTypeOfFunctionAtLoc loc ~(env : QueryEnv.t) ~full ~debug =
1161+
match References.getLocItem ~full ~pos:(loc |> Loc.end_) ~debug with
1162+
| Some {locType = Typed (_, typExpr, _)} -> (
1163+
match extractFunctionType ~env ~package:full.package typExpr with
1164+
| args, tRet when args <> [] -> Some tRet
1165+
| _ -> None)
1166+
| _ -> None
1167+
1168+
let rec getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
1169+
~exact ~scope (contextPath : Completable.contextPath) =
1170+
let package = full.package in
11621171
match contextPath with
11631172
| CPString ->
11641173
[
@@ -1181,8 +1190,8 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
11811190
| CPApply (cp, labels) -> (
11821191
match
11831192
cp
1184-
|> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
1185-
~env ~exact:true ~scope
1193+
|> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
1194+
~exact:true ~scope
11861195
|> completionsGetTypeEnv
11871196
with
11881197
| Some (typ, env) -> (
@@ -1227,8 +1236,8 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
12271236
| CPField (cp, fieldName) -> (
12281237
match
12291238
cp
1230-
|> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
1231-
~env ~exact:true ~scope
1239+
|> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
1240+
~exact:true ~scope
12321241
|> completionsGetTypeEnv
12331242
with
12341243
| Some (typ, env) -> (
@@ -1250,8 +1259,8 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
12501259
| CPObj (cp, label) -> (
12511260
match
12521261
cp
1253-
|> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
1254-
~env ~exact:true ~scope
1262+
|> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
1263+
~exact:true ~scope
12551264
|> completionsGetTypeEnv
12561265
with
12571266
| Some (typ, env) -> (
@@ -1275,14 +1284,28 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
12751284
else None)
12761285
| None -> [])
12771286
| None -> [])
1278-
| CPPipe (cp, funNamePrefix) -> (
1287+
| CPPipe {contextPath = cp; id = funNamePrefix; lhsLoc} -> (
12791288
match
12801289
cp
1281-
|> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
1282-
~env ~exact:true ~scope
1290+
|> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
1291+
~exact:true ~scope
12831292
|> completionsGetTypeEnv
12841293
with
12851294
| Some (typ, envFromCompletionItem) -> (
1295+
(* If the type we're completing on is a type parameter, we won't be able to do
1296+
completion unless we know what that type parameter is compiled as. This
1297+
attempts to look up the compiled type for that type parameter by looking
1298+
for compiled information at the loc of that expression. *)
1299+
let typ =
1300+
match typ with
1301+
| {Types.desc = Tvar _} -> (
1302+
match
1303+
findReturnTypeOfFunctionAtLoc lhsLoc ~env ~full ~debug:false
1304+
with
1305+
| None -> typ
1306+
| Some typFromLoc -> typFromLoc)
1307+
| _ -> typ
1308+
in
12861309
let {
12871310
arrayModulePath;
12881311
optionModulePath;
@@ -1418,8 +1441,9 @@ let getOpens ~debug ~rawOpens ~package ~env =
14181441
(* Last open takes priority *)
14191442
List.rev resolvedOpens
14201443

1421-
let processCompletable ~debug ~package ~scope ~env ~pos ~forHover
1444+
let processCompletable ~debug ~full ~scope ~env ~pos ~forHover
14221445
(completable : Completable.t) =
1446+
let package = full.package in
14231447
let rawOpens = Scope.getRawOpens scope in
14241448
let opens = getOpens ~debug ~rawOpens ~package ~env in
14251449
let allFiles = FileSet.union package.projectFiles package.dependenciesFiles in
@@ -1433,8 +1457,8 @@ let processCompletable ~debug ~package ~scope ~env ~pos ~forHover
14331457
| Cnone -> []
14341458
| Cpath contextPath ->
14351459
contextPath
1436-
|> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
1437-
~env ~exact:forHover ~scope
1460+
|> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
1461+
~exact:forHover ~scope
14381462
| Cjsx ([id], prefix, identsSeen) when String.uncapitalize_ascii id = id ->
14391463
let mkLabel (name, typString) =
14401464
Completion.create ~name ~kind:(Label typString) ~env
@@ -1783,7 +1807,7 @@ Note: The `@react.component` decorator requires the react-jsx config to be set i
17831807
let labels =
17841808
match
17851809
cp
1786-
|> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
1810+
|> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos
17871811
~env ~exact:true ~scope
17881812
|> completionsGetTypeEnv
17891813
with

analysis/src/CompletionFrontEnd.ml

+6-3
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ let completePipeChain ~(lhs : Parsetree.expression) =
180180
pexp_loc;
181181
pexp_attributes;
182182
}
183+
|> Option.map (fun ctxPath -> (ctxPath, d.pexp_loc))
183184
(* When the left side of the pipe we're completing is an identifier application.
184185
Example: someArray->filterAllTheGoodStuff-> *)
185186
| Pexp_apply
@@ -195,6 +196,7 @@ let completePipeChain ~(lhs : Parsetree.expression) =
195196
pexp_loc;
196197
pexp_attributes;
197198
}
199+
|> Option.map (fun ctxPath -> (ctxPath, pexp_loc))
198200
| _ -> None
199201

200202
let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text =
@@ -436,11 +438,12 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text =
436438
| None -> (
437439
match exprToContextPath lhs with
438440
| Some pipe ->
439-
setResult (Cpath (CPPipe (pipe, id)));
441+
setResult
442+
(Cpath (CPPipe {contextPath = pipe; id; lhsLoc = lhs.pexp_loc}));
440443
true
441444
| None -> false)
442-
| Some pipe ->
443-
setResult (Cpath (CPPipe (pipe, id)));
445+
| Some (pipe, lhsLoc) ->
446+
setResult (Cpath (CPPipe {contextPath = pipe; id; lhsLoc}));
444447
true
445448
in
446449
match expr.pexp_desc with

analysis/src/Hover.ml

+4-3
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,13 @@ let getHoverViaCompletions ~debug ~path ~pos ~currentFile ~forHover
136136
(* Only perform expensive ast operations if there are completables *)
137137
match Cmt.loadFullCmtFromPath ~path with
138138
| None -> None
139-
| Some {file; package} -> (
139+
| Some full -> (
140+
let {file; package} = full in
140141
let env = SharedTypes.QueryEnv.fromFile file in
141142
let completions =
142143
completable
143-
|> CompletionBackEnd.processCompletable ~debug ~package ~pos ~scope
144-
~env ~forHover
144+
|> CompletionBackEnd.processCompletable ~debug ~full ~pos ~scope ~env
145+
~forHover
145146
in
146147
match completions with
147148
| {kind = Label typString; docstring} :: _ ->

analysis/src/SharedTypes.ml

+7-2
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,12 @@ module Completable = struct
479479
| CPId of string list * completionContext
480480
| CPField of contextPath * string
481481
| CPObj of contextPath * string
482-
| CPPipe of contextPath * string
482+
| CPPipe of {
483+
contextPath: contextPath;
484+
id: string;
485+
lhsLoc: Location.t;
486+
(** The loc item for the left hand side of the pipe. *)
487+
}
483488

484489
type t =
485490
| Cdecorator of string (** e.g. @module *)
@@ -513,7 +518,7 @@ module Completable = struct
513518
completionContextToString completionContext ^ list sl
514519
| CPField (cp, s) -> contextPathToString cp ^ "." ^ str s
515520
| CPObj (cp, s) -> contextPathToString cp ^ "[\"" ^ s ^ "\"]"
516-
| CPPipe (cp, s) -> contextPathToString cp ^ "->" ^ s
521+
| CPPipe {contextPath; id} -> contextPathToString contextPath ^ "->" ^ id
517522
in
518523
function
519524
| Cpath cp -> "Cpath " ^ contextPathToString cp

analysis/src/SignatureHelp.ml

+4-3
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ let findFunctionType ~currentFile ~debug ~path ~pos =
1818
| Some (completable, scope) -> (
1919
match Cmt.loadFullCmtFromPath ~path with
2020
| None -> None
21-
| Some {file; package} ->
21+
| Some full ->
22+
let {file; package} = full in
2223
let env = QueryEnv.fromFile file in
2324
Some
2425
( completable
25-
|> CompletionBackEnd.processCompletable ~debug ~package ~pos
26-
~scope ~env ~forHover:true,
26+
|> CompletionBackEnd.processCompletable ~debug ~full ~pos ~scope
27+
~env ~forHover:true,
2728
env,
2829
package,
2930
file )))

analysis/tests/src/CompletionPipeChain.res

+4
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,7 @@ let f = int->Integer.increment(2)
5858
let _ = [123]->Js.Array2.forEach(v => Js.log(v))
5959
// ->
6060
// ^com
61+
62+
let _ = [123]->Belt.Array.reduce(0, (acc, curr) => acc + curr)
63+
// ->t
64+
// ^com

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

+17
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,20 @@ posCursor:[58:5] posNoWhite:[58:4] Found expr:[57:8->0:-1]
239239
Completable: Cpath Value[Js, Array2, forEach](Nolabel, Nolabel)->
240240
[]
241241

242+
Complete src/CompletionPipeChain.res 62:6
243+
posCursor:[62:6] posNoWhite:[62:5] Found expr:[61:8->62:6]
244+
Completable: Cpath Value[Belt, Array, reduce](Nolabel, Nolabel, Nolabel)->t
245+
[{
246+
"label": "Belt.Int.toString",
247+
"kind": 12,
248+
"tags": [],
249+
"detail": "int => string",
250+
"documentation": {"kind": "markdown", "value": "\n Converts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n ```res example\n Js.log(Belt.Int.toString(1) === \"1\") /* true */\n ```\n"}
251+
}, {
252+
"label": "Belt.Int.toFloat",
253+
"kind": 12,
254+
"tags": [],
255+
"detail": "int => float",
256+
"documentation": {"kind": "markdown", "value": "\n Converts a given `int` to a `float`.\n\n ```res example\n Js.log(Belt.Int.toFloat(1) === 1.0) /* true */\n ```\n"}
257+
}]
258+

0 commit comments

Comments
 (0)