diff --git a/README.md b/README.md
index e67a69018..e67716011 100644
--- a/README.md
+++ b/README.md
@@ -4,13 +4,6 @@
The Official VSCode plugin for ReScript
-
-
-
-
-
-
-
diff --git a/analysis/src/Commands.ml b/analysis/src/Commands.ml
index 756c6fb43..db671ca08 100644
--- a/analysis/src/Commands.ml
+++ b/analysis/src/Commands.ml
@@ -15,10 +15,10 @@ let getCompletions ~debug ~path ~pos ~currentFile ~forHover =
(* Only perform expensive ast operations if there are completables *)
match Cmt.loadFullCmtFromPath ~path with
| None -> []
- | Some {file; package} ->
- let env = SharedTypes.QueryEnv.fromFile file in
+ | Some full ->
+ let env = SharedTypes.QueryEnv.fromFile full.file in
completable
- |> CompletionBackEnd.processCompletable ~debug ~package ~pos ~scope ~env
+ |> CompletionBackEnd.processCompletable ~debug ~full ~pos ~scope ~env
~forHover))
let completion ~debug ~path ~pos ~currentFile =
diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml
index 10463e787..2b588784a 100644
--- a/analysis/src/CompletionBackEnd.ml
+++ b/analysis/src/CompletionBackEnd.ml
@@ -1157,8 +1157,17 @@ let completionsGetTypeEnv = function
| {Completion.kind = Field ({typ}, _); env} :: _ -> Some (typ, env)
| _ -> None
-let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
- ~env ~exact ~scope (contextPath : Completable.contextPath) =
+let findReturnTypeOfFunctionAtLoc loc ~(env : QueryEnv.t) ~full ~debug =
+ match References.getLocItem ~full ~pos:(loc |> Loc.end_) ~debug with
+ | Some {locType = Typed (_, typExpr, _)} -> (
+ match extractFunctionType ~env ~package:full.package typExpr with
+ | args, tRet when args <> [] -> Some tRet
+ | _ -> None)
+ | _ -> None
+
+let rec getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
+ ~exact ~scope (contextPath : Completable.contextPath) =
+ let package = full.package in
match contextPath with
| CPString ->
[
@@ -1181,8 +1190,8 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
| CPApply (cp, labels) -> (
match
cp
- |> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
- ~env ~exact:true ~scope
+ |> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
+ ~exact:true ~scope
|> completionsGetTypeEnv
with
| Some (typ, env) -> (
@@ -1227,8 +1236,8 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
| CPField (cp, fieldName) -> (
match
cp
- |> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
- ~env ~exact:true ~scope
+ |> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
+ ~exact:true ~scope
|> completionsGetTypeEnv
with
| Some (typ, env) -> (
@@ -1250,8 +1259,8 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
| CPObj (cp, label) -> (
match
cp
- |> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
- ~env ~exact:true ~scope
+ |> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
+ ~exact:true ~scope
|> completionsGetTypeEnv
with
| Some (typ, env) -> (
@@ -1275,14 +1284,28 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
else None)
| None -> [])
| None -> [])
- | CPPipe (cp, funNamePrefix) -> (
+ | CPPipe {contextPath = cp; id = funNamePrefix; lhsLoc} -> (
match
cp
- |> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
- ~env ~exact:true ~scope
+ |> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
+ ~exact:true ~scope
|> completionsGetTypeEnv
with
| Some (typ, envFromCompletionItem) -> (
+ (* If the type we're completing on is a type parameter, we won't be able to do
+ completion unless we know what that type parameter is compiled as. This
+ attempts to look up the compiled type for that type parameter by looking
+ for compiled information at the loc of that expression. *)
+ let typ =
+ match typ with
+ | {Types.desc = Tvar _} -> (
+ match
+ findReturnTypeOfFunctionAtLoc lhsLoc ~env ~full ~debug:false
+ with
+ | None -> typ
+ | Some typFromLoc -> typFromLoc)
+ | _ -> typ
+ in
let {
arrayModulePath;
optionModulePath;
@@ -1418,8 +1441,9 @@ let getOpens ~debug ~rawOpens ~package ~env =
(* Last open takes priority *)
List.rev resolvedOpens
-let processCompletable ~debug ~package ~scope ~env ~pos ~forHover
+let processCompletable ~debug ~full ~scope ~env ~pos ~forHover
(completable : Completable.t) =
+ let package = full.package in
let rawOpens = Scope.getRawOpens scope in
let opens = getOpens ~debug ~rawOpens ~package ~env in
let allFiles = FileSet.union package.projectFiles package.dependenciesFiles in
@@ -1433,8 +1457,8 @@ let processCompletable ~debug ~package ~scope ~env ~pos ~forHover
| Cnone -> []
| Cpath contextPath ->
contextPath
- |> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
- ~env ~exact:forHover ~scope
+ |> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
+ ~exact:forHover ~scope
| Cjsx ([id], prefix, identsSeen) when String.uncapitalize_ascii id = id ->
let mkLabel (name, typString) =
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
let labels =
match
cp
- |> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
+ |> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos
~env ~exact:true ~scope
|> completionsGetTypeEnv
with
diff --git a/analysis/src/CompletionFrontEnd.ml b/analysis/src/CompletionFrontEnd.ml
index d7f12cac5..d9509abde 100644
--- a/analysis/src/CompletionFrontEnd.ml
+++ b/analysis/src/CompletionFrontEnd.ml
@@ -180,6 +180,7 @@ let completePipeChain ~(lhs : Parsetree.expression) =
pexp_loc;
pexp_attributes;
}
+ |> Option.map (fun ctxPath -> (ctxPath, d.pexp_loc))
(* When the left side of the pipe we're completing is an identifier application.
Example: someArray->filterAllTheGoodStuff-> *)
| Pexp_apply
@@ -195,6 +196,7 @@ let completePipeChain ~(lhs : Parsetree.expression) =
pexp_loc;
pexp_attributes;
}
+ |> Option.map (fun ctxPath -> (ctxPath, pexp_loc))
| _ -> None
let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text =
@@ -436,11 +438,12 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text =
| None -> (
match exprToContextPath lhs with
| Some pipe ->
- setResult (Cpath (CPPipe (pipe, id)));
+ setResult
+ (Cpath (CPPipe {contextPath = pipe; id; lhsLoc = lhs.pexp_loc}));
true
| None -> false)
- | Some pipe ->
- setResult (Cpath (CPPipe (pipe, id)));
+ | Some (pipe, lhsLoc) ->
+ setResult (Cpath (CPPipe {contextPath = pipe; id; lhsLoc}));
true
in
match expr.pexp_desc with
diff --git a/analysis/src/Hover.ml b/analysis/src/Hover.ml
index 599852273..2cfeb8348 100644
--- a/analysis/src/Hover.ml
+++ b/analysis/src/Hover.ml
@@ -136,12 +136,13 @@ let getHoverViaCompletions ~debug ~path ~pos ~currentFile ~forHover
(* Only perform expensive ast operations if there are completables *)
match Cmt.loadFullCmtFromPath ~path with
| None -> None
- | Some {file; package} -> (
+ | Some full -> (
+ let {file; package} = full in
let env = SharedTypes.QueryEnv.fromFile file in
let completions =
completable
- |> CompletionBackEnd.processCompletable ~debug ~package ~pos ~scope
- ~env ~forHover
+ |> CompletionBackEnd.processCompletable ~debug ~full ~pos ~scope ~env
+ ~forHover
in
match completions with
| {kind = Label typString; docstring} :: _ ->
diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml
index e5ee97e9f..ac56eed2f 100644
--- a/analysis/src/SharedTypes.ml
+++ b/analysis/src/SharedTypes.ml
@@ -479,7 +479,12 @@ module Completable = struct
| CPId of string list * completionContext
| CPField of contextPath * string
| CPObj of contextPath * string
- | CPPipe of contextPath * string
+ | CPPipe of {
+ contextPath: contextPath;
+ id: string;
+ lhsLoc: Location.t;
+ (** The loc item for the left hand side of the pipe. *)
+ }
type t =
| Cdecorator of string (** e.g. @module *)
@@ -513,7 +518,7 @@ module Completable = struct
completionContextToString completionContext ^ list sl
| CPField (cp, s) -> contextPathToString cp ^ "." ^ str s
| CPObj (cp, s) -> contextPathToString cp ^ "[\"" ^ s ^ "\"]"
- | CPPipe (cp, s) -> contextPathToString cp ^ "->" ^ s
+ | CPPipe {contextPath; id} -> contextPathToString contextPath ^ "->" ^ id
in
function
| Cpath cp -> "Cpath " ^ contextPathToString cp
diff --git a/analysis/src/SignatureHelp.ml b/analysis/src/SignatureHelp.ml
index 364d463b2..69a0ff006 100644
--- a/analysis/src/SignatureHelp.ml
+++ b/analysis/src/SignatureHelp.ml
@@ -18,12 +18,13 @@ let findFunctionType ~currentFile ~debug ~path ~pos =
| Some (completable, scope) -> (
match Cmt.loadFullCmtFromPath ~path with
| None -> None
- | Some {file; package} ->
+ | Some full ->
+ let {file; package} = full in
let env = QueryEnv.fromFile file in
Some
( completable
- |> CompletionBackEnd.processCompletable ~debug ~package ~pos
- ~scope ~env ~forHover:true,
+ |> CompletionBackEnd.processCompletable ~debug ~full ~pos ~scope
+ ~env ~forHover:true,
env,
package,
file )))
diff --git a/analysis/tests/src/CompletionPipeChain.res b/analysis/tests/src/CompletionPipeChain.res
index 59c1af258..f9bcd2345 100644
--- a/analysis/tests/src/CompletionPipeChain.res
+++ b/analysis/tests/src/CompletionPipeChain.res
@@ -58,3 +58,7 @@ let f = int->Integer.increment(2)
let _ = [123]->Js.Array2.forEach(v => Js.log(v))
// ->
// ^com
+
+let _ = [123]->Belt.Array.reduce(0, (acc, curr) => acc + curr)
+// ->t
+// ^com
diff --git a/analysis/tests/src/expected/CompletionPipeChain.res.txt b/analysis/tests/src/expected/CompletionPipeChain.res.txt
index fe947a437..c7cff492f 100644
--- a/analysis/tests/src/expected/CompletionPipeChain.res.txt
+++ b/analysis/tests/src/expected/CompletionPipeChain.res.txt
@@ -239,3 +239,20 @@ posCursor:[58:5] posNoWhite:[58:4] Found expr:[57:8->0:-1]
Completable: Cpath Value[Js, Array2, forEach](Nolabel, Nolabel)->
[]
+Complete src/CompletionPipeChain.res 62:6
+posCursor:[62:6] posNoWhite:[62:5] Found expr:[61:8->62:6]
+Completable: Cpath Value[Belt, Array, reduce](Nolabel, Nolabel, Nolabel)->t
+[{
+ "label": "Belt.Int.toString",
+ "kind": 12,
+ "tags": [],
+ "detail": "int => string",
+ "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"}
+ }, {
+ "label": "Belt.Int.toFloat",
+ "kind": 12,
+ "tags": [],
+ "detail": "int => float",
+ "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"}
+ }]
+