From 06468ba1cd35737f3f1dc55f56c2cae6b2ad1bcb Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Wed, 21 Dec 2022 22:08:20 +0100
Subject: [PATCH 01/14] add test demonstrating that pipe completion with an
 unknown return type does not work, not even after compilation

---
 analysis/tests/src/CompletionPipeChain.res              | 4 ++++
 analysis/tests/src/expected/CompletionPipeChain.res.txt | 5 +++++
 2 files changed, 9 insertions(+)

diff --git a/analysis/tests/src/CompletionPipeChain.res b/analysis/tests/src/CompletionPipeChain.res
index 59c1af258..3c48f27fa 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)
+// ->
+//   ^com
diff --git a/analysis/tests/src/expected/CompletionPipeChain.res.txt b/analysis/tests/src/expected/CompletionPipeChain.res.txt
index fe947a437..18adb063b 100644
--- a/analysis/tests/src/expected/CompletionPipeChain.res.txt
+++ b/analysis/tests/src/expected/CompletionPipeChain.res.txt
@@ -239,3 +239,8 @@ 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:5
+posCursor:[62:5] posNoWhite:[62:4] Found expr:[61:8->0:-1]
+Completable: Cpath Value[Belt, Array, reduce](Nolabel, Nolabel, Nolabel)->
+[]
+

From af5d85ac0bbeb222e8b3f17fc3128a2bade149d9 Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Wed, 21 Dec 2022 22:13:05 +0100
Subject: [PATCH 02/14] make CPPipe take inline record

---
 analysis/src/CompletionBackEnd.ml  | 2 +-
 analysis/src/CompletionFrontEnd.ml | 4 ++--
 analysis/src/SharedTypes.ml        | 4 ++--
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml
index 10463e787..0772eeb7c 100644
--- a/analysis/src/CompletionBackEnd.ml
+++ b/analysis/src/CompletionBackEnd.ml
@@ -1275,7 +1275,7 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
                else None)
       | None -> [])
     | None -> [])
-  | CPPipe (cp, funNamePrefix) -> (
+  | CPPipe {contextPath = cp; id = funNamePrefix} -> (
     match
       cp
       |> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
diff --git a/analysis/src/CompletionFrontEnd.ml b/analysis/src/CompletionFrontEnd.ml
index d7f12cac5..fd34755e5 100644
--- a/analysis/src/CompletionFrontEnd.ml
+++ b/analysis/src/CompletionFrontEnd.ml
@@ -436,11 +436,11 @@ 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}));
           true
         | None -> false)
       | Some pipe ->
-        setResult (Cpath (CPPipe (pipe, id)));
+        setResult (Cpath (CPPipe {contextPath = pipe; id}));
         true
     in
     match expr.pexp_desc with
diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml
index e5ee97e9f..77ea64373 100644
--- a/analysis/src/SharedTypes.ml
+++ b/analysis/src/SharedTypes.ml
@@ -479,7 +479,7 @@ 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}
 
   type t =
     | Cdecorator of string  (** e.g. @module *)
@@ -513,7 +513,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

From 488df414bea529b109bbf1bda43ce74dcbc6792c Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Wed, 21 Dec 2022 22:17:20 +0100
Subject: [PATCH 03/14] propagate loc of lhs in pipe completion

---
 analysis/src/CompletionFrontEnd.ml | 9 ++++++---
 analysis/src/SharedTypes.ml        | 2 +-
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/analysis/src/CompletionFrontEnd.ml b/analysis/src/CompletionFrontEnd.ml
index fd34755e5..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 {contextPath = pipe; id}));
+          setResult
+            (Cpath (CPPipe {contextPath = pipe; id; lhsLoc = lhs.pexp_loc}));
           true
         | None -> false)
-      | Some pipe ->
-        setResult (Cpath (CPPipe {contextPath = pipe; id}));
+      | Some (pipe, lhsLoc) ->
+        setResult (Cpath (CPPipe {contextPath = pipe; id; lhsLoc}));
         true
     in
     match expr.pexp_desc with
diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml
index 77ea64373..dba389212 100644
--- a/analysis/src/SharedTypes.ml
+++ b/analysis/src/SharedTypes.ml
@@ -479,7 +479,7 @@ module Completable = struct
     | CPId of string list * completionContext
     | CPField of contextPath * string
     | CPObj of contextPath * string
-    | CPPipe of {contextPath: contextPath; id: string}
+    | CPPipe of {contextPath: contextPath; id: string; lhsLoc: Warnings.loc}
 
   type t =
     | Cdecorator of string  (** e.g. @module *)

From a705a86db5247841b12db4f9eeba1a7b9bec78aa Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Wed, 21 Dec 2022 22:29:52 +0100
Subject: [PATCH 04/14] look up compiled type parameter value when completing
 unknown type in pipe chain

---
 analysis/src/CompletionBackEnd.ml             | 25 +++++++++-
 .../src/expected/CompletionPipeChain.res.txt  | 50 ++++++++++++++++++-
 2 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml
index 0772eeb7c..0047df27a 100644
--- a/analysis/src/CompletionBackEnd.ml
+++ b/analysis/src/CompletionBackEnd.ml
@@ -1157,6 +1157,17 @@ let completionsGetTypeEnv = function
   | {Completion.kind = Field ({typ}, _); env} :: _ -> Some (typ, env)
   | _ -> None
 
+let findTypeAtLoc loc ~(env : QueryEnv.t) ~package ~debug =
+  match Cmt.loadFullCmtFromPath ~path:(env.file.uri |> Uri.toPath) with
+  | None -> None
+  | Some full -> (
+    match References.getLocItem ~full ~pos:(loc |> Loc.end_) ~debug with
+    | Some {locType = Typed (_, typExpr, _)} -> (
+      match extractFunctionType ~env ~package typExpr with
+      | args, tRet when args <> [] -> Some tRet
+      | _ -> None)
+    | _ -> None)
+
 let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
     ~env ~exact ~scope (contextPath : Completable.contextPath) =
   match contextPath with
@@ -1275,7 +1286,7 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
                else None)
       | None -> [])
     | None -> [])
-  | CPPipe {contextPath = cp; id = funNamePrefix} -> (
+  | CPPipe {contextPath = cp; id = funNamePrefix; lhsLoc} -> (
     match
       cp
       |> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
@@ -1283,6 +1294,18 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
       |> 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 findTypeAtLoc lhsLoc ~env ~package ~debug:false with
+          | None -> typ
+          | Some typFromLoc -> typFromLoc)
+        | _ -> typ
+      in
       let {
         arrayModulePath;
         optionModulePath;
diff --git a/analysis/tests/src/expected/CompletionPipeChain.res.txt b/analysis/tests/src/expected/CompletionPipeChain.res.txt
index 18adb063b..4c19282f3 100644
--- a/analysis/tests/src/expected/CompletionPipeChain.res.txt
+++ b/analysis/tests/src/expected/CompletionPipeChain.res.txt
@@ -242,5 +242,53 @@ Completable: Cpath Value[Js, Array2, forEach](Nolabel, Nolabel)->
 Complete src/CompletionPipeChain.res 62:5
 posCursor:[62:5] posNoWhite:[62:4] Found expr:[61:8->0:-1]
 Completable: Cpath Value[Belt, Array, reduce](Nolabel, Nolabel, Nolabel)->
-[]
+[{
+    "label": "Belt.Int.fromString",
+    "kind": 12,
+    "tags": [],
+    "detail": "string => option<int>",
+    "documentation": {"kind": "markdown", "value": "\n  Converts a given `string` to an `int`. Returns `Some(int)` when the input is a number, `None` otherwise.\n\n  ```res example\n  Js.log(Belt.Int.fromString(\"1\") === Some(1)) /* true */\n  ```\n"}
+  }, {
+    "label": "Belt.Int.*",
+    "kind": 12,
+    "tags": [],
+    "detail": "(int, int) => int",
+    "documentation": {"kind": "markdown", "value": "\n  Multiplication of two `int` values. Same as the multiplication from `Pervasives`.\n\n  ```res example\n  open Belt.Int\n  Js.log(2 * 2 === 4) /* true */\n  ```\n"}
+  }, {
+    "label": "Belt.Int./",
+    "kind": 12,
+    "tags": [],
+    "detail": "(int, int) => int",
+    "documentation": {"kind": "markdown", "value": "\n  Division of two `int` values. Same as the division from `Pervasives`.\n\n  ```res example\n  open Belt.Int\n  Js.log(4 / 2 === 2); /* true */\n  ```\n"}
+  }, {
+    "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"}
+  }, {
+    "label": "Belt.Int.fromFloat",
+    "kind": 12,
+    "tags": [],
+    "detail": "float => int",
+    "documentation": {"kind": "markdown", "value": "\n  Converts a given `float` to an `int`.\n\n  ```res example\n  Js.log(Belt.Int.fromFloat(1.0) === 1) /* true */\n  ```\n"}
+  }, {
+    "label": "Belt.Int.-",
+    "kind": 12,
+    "tags": [],
+    "detail": "(int, int) => int",
+    "documentation": {"kind": "markdown", "value": "\n  Subtraction of two `int` values. Same as the subtraction from `Pervasives`.\n\n  ```res example\n  open Belt.Int\n  Js.log(2 - 1 === 1) /* true */\n  ```\n"}
+  }, {
+    "label": "Belt.Int.+",
+    "kind": 12,
+    "tags": [],
+    "detail": "(int, int) => int",
+    "documentation": {"kind": "markdown", "value": "\n  Addition of two `int` values. Same as the addition from `Pervasives`.\n\n  ```res example\n  open Belt.Int\n  Js.log(2 + 2 === 4) /* true */\n  ```\n"}
+  }]
 

From c0e4b0c43fcf196bcd9bf2655465da7f31261325 Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Wed, 21 Dec 2022 22:31:27 +0100
Subject: [PATCH 05/14] more accurate function name

---
 analysis/src/CompletionBackEnd.ml | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml
index 0047df27a..e26a6f805 100644
--- a/analysis/src/CompletionBackEnd.ml
+++ b/analysis/src/CompletionBackEnd.ml
@@ -1157,7 +1157,7 @@ let completionsGetTypeEnv = function
   | {Completion.kind = Field ({typ}, _); env} :: _ -> Some (typ, env)
   | _ -> None
 
-let findTypeAtLoc loc ~(env : QueryEnv.t) ~package ~debug =
+let findReturnTypeOfFunctionAtLoc loc ~(env : QueryEnv.t) ~package ~debug =
   match Cmt.loadFullCmtFromPath ~path:(env.file.uri |> Uri.toPath) with
   | None -> None
   | Some full -> (
@@ -1301,7 +1301,9 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
       let typ =
         match typ with
         | {Types.desc = Tvar _} -> (
-          match findTypeAtLoc lhsLoc ~env ~package ~debug:false with
+          match
+            findReturnTypeOfFunctionAtLoc lhsLoc ~env ~package ~debug:false
+          with
           | None -> typ
           | Some typFromLoc -> typFromLoc)
         | _ -> typ

From ba532aca0f18dd6e68f7a8d63af68b22a8317c9c Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Wed, 21 Dec 2022 22:43:08 +0100
Subject: [PATCH 06/14] temp remove broken logo image links so extension can be
 published again

---
 README.md | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/README.md b/README.md
index e67a69018..e67716011 100644
--- a/README.md
+++ b/README.md
@@ -4,13 +4,6 @@
 
 <p align="center">The Official VSCode plugin for ReScript</p>
 
-<p align="center">
-  <a href="https://marketplace.visualstudio.com/items?itemName=chenglou92.rescript-vscode">
-    <img src="https://vsmarketplacebadge.apphb.com/version/chenglou92.rescript-vscode.svg"/>
-    <img src="https://vsmarketplacebadge.apphb.com/installs/chenglou92.rescript-vscode.svg"/>
-  </a>
-</p>
-
 <p align="center">
   <img src="https://user-images.githubusercontent.com/1909539/101266821-790b1400-3707-11eb-8e9f-fb7e36e660e6.gif"/>
 </p>

From f29cd71911581fd592eb01ddf4d79e9fffee9205 Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Wed, 21 Dec 2022 22:08:20 +0100
Subject: [PATCH 07/14] add test demonstrating that pipe completion with an
 unknown return type does not work, not even after compilation

---
 analysis/tests/src/CompletionPipeChain.res              | 4 ++++
 analysis/tests/src/expected/CompletionPipeChain.res.txt | 5 +++++
 2 files changed, 9 insertions(+)

diff --git a/analysis/tests/src/CompletionPipeChain.res b/analysis/tests/src/CompletionPipeChain.res
index 59c1af258..3c48f27fa 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)
+// ->
+//   ^com
diff --git a/analysis/tests/src/expected/CompletionPipeChain.res.txt b/analysis/tests/src/expected/CompletionPipeChain.res.txt
index fe947a437..18adb063b 100644
--- a/analysis/tests/src/expected/CompletionPipeChain.res.txt
+++ b/analysis/tests/src/expected/CompletionPipeChain.res.txt
@@ -239,3 +239,8 @@ 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:5
+posCursor:[62:5] posNoWhite:[62:4] Found expr:[61:8->0:-1]
+Completable: Cpath Value[Belt, Array, reduce](Nolabel, Nolabel, Nolabel)->
+[]
+

From abc4794517334be9749b7538b5f95fc26e60c9eb Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Wed, 21 Dec 2022 22:13:05 +0100
Subject: [PATCH 08/14] make CPPipe take inline record

---
 analysis/src/CompletionBackEnd.ml  | 2 +-
 analysis/src/CompletionFrontEnd.ml | 4 ++--
 analysis/src/SharedTypes.ml        | 4 ++--
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml
index 10463e787..0772eeb7c 100644
--- a/analysis/src/CompletionBackEnd.ml
+++ b/analysis/src/CompletionBackEnd.ml
@@ -1275,7 +1275,7 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
                else None)
       | None -> [])
     | None -> [])
-  | CPPipe (cp, funNamePrefix) -> (
+  | CPPipe {contextPath = cp; id = funNamePrefix} -> (
     match
       cp
       |> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
diff --git a/analysis/src/CompletionFrontEnd.ml b/analysis/src/CompletionFrontEnd.ml
index d7f12cac5..fd34755e5 100644
--- a/analysis/src/CompletionFrontEnd.ml
+++ b/analysis/src/CompletionFrontEnd.ml
@@ -436,11 +436,11 @@ 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}));
           true
         | None -> false)
       | Some pipe ->
-        setResult (Cpath (CPPipe (pipe, id)));
+        setResult (Cpath (CPPipe {contextPath = pipe; id}));
         true
     in
     match expr.pexp_desc with
diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml
index e5ee97e9f..77ea64373 100644
--- a/analysis/src/SharedTypes.ml
+++ b/analysis/src/SharedTypes.ml
@@ -479,7 +479,7 @@ 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}
 
   type t =
     | Cdecorator of string  (** e.g. @module *)
@@ -513,7 +513,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

From 6e3618773e34d48d517b1996b0979e689def2500 Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Wed, 21 Dec 2022 22:17:20 +0100
Subject: [PATCH 09/14] propagate loc of lhs in pipe completion

---
 analysis/src/CompletionFrontEnd.ml | 9 ++++++---
 analysis/src/SharedTypes.ml        | 2 +-
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/analysis/src/CompletionFrontEnd.ml b/analysis/src/CompletionFrontEnd.ml
index fd34755e5..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 {contextPath = pipe; id}));
+          setResult
+            (Cpath (CPPipe {contextPath = pipe; id; lhsLoc = lhs.pexp_loc}));
           true
         | None -> false)
-      | Some pipe ->
-        setResult (Cpath (CPPipe {contextPath = pipe; id}));
+      | Some (pipe, lhsLoc) ->
+        setResult (Cpath (CPPipe {contextPath = pipe; id; lhsLoc}));
         true
     in
     match expr.pexp_desc with
diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml
index 77ea64373..dba389212 100644
--- a/analysis/src/SharedTypes.ml
+++ b/analysis/src/SharedTypes.ml
@@ -479,7 +479,7 @@ module Completable = struct
     | CPId of string list * completionContext
     | CPField of contextPath * string
     | CPObj of contextPath * string
-    | CPPipe of {contextPath: contextPath; id: string}
+    | CPPipe of {contextPath: contextPath; id: string; lhsLoc: Warnings.loc}
 
   type t =
     | Cdecorator of string  (** e.g. @module *)

From f7ee910000b42691a415bf3ab54957a13d81b573 Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Wed, 21 Dec 2022 22:29:52 +0100
Subject: [PATCH 10/14] look up compiled type parameter value when completing
 unknown type in pipe chain

---
 analysis/src/CompletionBackEnd.ml             | 25 +++++++++-
 .../src/expected/CompletionPipeChain.res.txt  | 50 ++++++++++++++++++-
 2 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml
index 0772eeb7c..0047df27a 100644
--- a/analysis/src/CompletionBackEnd.ml
+++ b/analysis/src/CompletionBackEnd.ml
@@ -1157,6 +1157,17 @@ let completionsGetTypeEnv = function
   | {Completion.kind = Field ({typ}, _); env} :: _ -> Some (typ, env)
   | _ -> None
 
+let findTypeAtLoc loc ~(env : QueryEnv.t) ~package ~debug =
+  match Cmt.loadFullCmtFromPath ~path:(env.file.uri |> Uri.toPath) with
+  | None -> None
+  | Some full -> (
+    match References.getLocItem ~full ~pos:(loc |> Loc.end_) ~debug with
+    | Some {locType = Typed (_, typExpr, _)} -> (
+      match extractFunctionType ~env ~package typExpr with
+      | args, tRet when args <> [] -> Some tRet
+      | _ -> None)
+    | _ -> None)
+
 let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
     ~env ~exact ~scope (contextPath : Completable.contextPath) =
   match contextPath with
@@ -1275,7 +1286,7 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
                else None)
       | None -> [])
     | None -> [])
-  | CPPipe {contextPath = cp; id = funNamePrefix} -> (
+  | CPPipe {contextPath = cp; id = funNamePrefix; lhsLoc} -> (
     match
       cp
       |> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
@@ -1283,6 +1294,18 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
       |> 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 findTypeAtLoc lhsLoc ~env ~package ~debug:false with
+          | None -> typ
+          | Some typFromLoc -> typFromLoc)
+        | _ -> typ
+      in
       let {
         arrayModulePath;
         optionModulePath;
diff --git a/analysis/tests/src/expected/CompletionPipeChain.res.txt b/analysis/tests/src/expected/CompletionPipeChain.res.txt
index 18adb063b..4c19282f3 100644
--- a/analysis/tests/src/expected/CompletionPipeChain.res.txt
+++ b/analysis/tests/src/expected/CompletionPipeChain.res.txt
@@ -242,5 +242,53 @@ Completable: Cpath Value[Js, Array2, forEach](Nolabel, Nolabel)->
 Complete src/CompletionPipeChain.res 62:5
 posCursor:[62:5] posNoWhite:[62:4] Found expr:[61:8->0:-1]
 Completable: Cpath Value[Belt, Array, reduce](Nolabel, Nolabel, Nolabel)->
-[]
+[{
+    "label": "Belt.Int.fromString",
+    "kind": 12,
+    "tags": [],
+    "detail": "string => option<int>",
+    "documentation": {"kind": "markdown", "value": "\n  Converts a given `string` to an `int`. Returns `Some(int)` when the input is a number, `None` otherwise.\n\n  ```res example\n  Js.log(Belt.Int.fromString(\"1\") === Some(1)) /* true */\n  ```\n"}
+  }, {
+    "label": "Belt.Int.*",
+    "kind": 12,
+    "tags": [],
+    "detail": "(int, int) => int",
+    "documentation": {"kind": "markdown", "value": "\n  Multiplication of two `int` values. Same as the multiplication from `Pervasives`.\n\n  ```res example\n  open Belt.Int\n  Js.log(2 * 2 === 4) /* true */\n  ```\n"}
+  }, {
+    "label": "Belt.Int./",
+    "kind": 12,
+    "tags": [],
+    "detail": "(int, int) => int",
+    "documentation": {"kind": "markdown", "value": "\n  Division of two `int` values. Same as the division from `Pervasives`.\n\n  ```res example\n  open Belt.Int\n  Js.log(4 / 2 === 2); /* true */\n  ```\n"}
+  }, {
+    "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"}
+  }, {
+    "label": "Belt.Int.fromFloat",
+    "kind": 12,
+    "tags": [],
+    "detail": "float => int",
+    "documentation": {"kind": "markdown", "value": "\n  Converts a given `float` to an `int`.\n\n  ```res example\n  Js.log(Belt.Int.fromFloat(1.0) === 1) /* true */\n  ```\n"}
+  }, {
+    "label": "Belt.Int.-",
+    "kind": 12,
+    "tags": [],
+    "detail": "(int, int) => int",
+    "documentation": {"kind": "markdown", "value": "\n  Subtraction of two `int` values. Same as the subtraction from `Pervasives`.\n\n  ```res example\n  open Belt.Int\n  Js.log(2 - 1 === 1) /* true */\n  ```\n"}
+  }, {
+    "label": "Belt.Int.+",
+    "kind": 12,
+    "tags": [],
+    "detail": "(int, int) => int",
+    "documentation": {"kind": "markdown", "value": "\n  Addition of two `int` values. Same as the addition from `Pervasives`.\n\n  ```res example\n  open Belt.Int\n  Js.log(2 + 2 === 4) /* true */\n  ```\n"}
+  }]
 

From 6c94636bc7c0bcc77bd2c547f687a533ea508583 Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Wed, 21 Dec 2022 22:31:27 +0100
Subject: [PATCH 11/14] more accurate function name

---
 analysis/src/CompletionBackEnd.ml | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml
index 0047df27a..e26a6f805 100644
--- a/analysis/src/CompletionBackEnd.ml
+++ b/analysis/src/CompletionBackEnd.ml
@@ -1157,7 +1157,7 @@ let completionsGetTypeEnv = function
   | {Completion.kind = Field ({typ}, _); env} :: _ -> Some (typ, env)
   | _ -> None
 
-let findTypeAtLoc loc ~(env : QueryEnv.t) ~package ~debug =
+let findReturnTypeOfFunctionAtLoc loc ~(env : QueryEnv.t) ~package ~debug =
   match Cmt.loadFullCmtFromPath ~path:(env.file.uri |> Uri.toPath) with
   | None -> None
   | Some full -> (
@@ -1301,7 +1301,9 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
       let typ =
         match typ with
         | {Types.desc = Tvar _} -> (
-          match findTypeAtLoc lhsLoc ~env ~package ~debug:false with
+          match
+            findReturnTypeOfFunctionAtLoc lhsLoc ~env ~package ~debug:false
+          with
           | None -> typ
           | Some typFromLoc -> typFromLoc)
         | _ -> typ

From 88f4d171f76851ae1d4a5c9bde6dfb363ea8ded0 Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Thu, 22 Dec 2022 13:11:10 +0100
Subject: [PATCH 12/14] Warnings.loc -> Location.t

---
 analysis/src/SharedTypes.ml | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml
index dba389212..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: contextPath; id: string; lhsLoc: Warnings.loc}
+    | 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 *)

From 511f75679474c98fad5216351a6c1c98a2033852 Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Thu, 22 Dec 2022 13:11:49 +0100
Subject: [PATCH 13/14] shorten test output

---
 analysis/tests/src/CompletionPipeChain.res    |  4 +-
 .../src/expected/CompletionPipeChain.res.txt  | 42 ++-----------------
 2 files changed, 5 insertions(+), 41 deletions(-)

diff --git a/analysis/tests/src/CompletionPipeChain.res b/analysis/tests/src/CompletionPipeChain.res
index 3c48f27fa..f9bcd2345 100644
--- a/analysis/tests/src/CompletionPipeChain.res
+++ b/analysis/tests/src/CompletionPipeChain.res
@@ -60,5 +60,5 @@ let _ = [123]->Js.Array2.forEach(v => Js.log(v))
 //   ^com
 
 let _ = [123]->Belt.Array.reduce(0, (acc, curr) => acc + curr)
-// ->
-//   ^com
+// ->t
+//    ^com
diff --git a/analysis/tests/src/expected/CompletionPipeChain.res.txt b/analysis/tests/src/expected/CompletionPipeChain.res.txt
index 4c19282f3..c7cff492f 100644
--- a/analysis/tests/src/expected/CompletionPipeChain.res.txt
+++ b/analysis/tests/src/expected/CompletionPipeChain.res.txt
@@ -239,28 +239,10 @@ 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:5
-posCursor:[62:5] posNoWhite:[62:4] Found expr:[61:8->0:-1]
-Completable: Cpath Value[Belt, Array, reduce](Nolabel, 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.fromString",
-    "kind": 12,
-    "tags": [],
-    "detail": "string => option<int>",
-    "documentation": {"kind": "markdown", "value": "\n  Converts a given `string` to an `int`. Returns `Some(int)` when the input is a number, `None` otherwise.\n\n  ```res example\n  Js.log(Belt.Int.fromString(\"1\") === Some(1)) /* true */\n  ```\n"}
-  }, {
-    "label": "Belt.Int.*",
-    "kind": 12,
-    "tags": [],
-    "detail": "(int, int) => int",
-    "documentation": {"kind": "markdown", "value": "\n  Multiplication of two `int` values. Same as the multiplication from `Pervasives`.\n\n  ```res example\n  open Belt.Int\n  Js.log(2 * 2 === 4) /* true */\n  ```\n"}
-  }, {
-    "label": "Belt.Int./",
-    "kind": 12,
-    "tags": [],
-    "detail": "(int, int) => int",
-    "documentation": {"kind": "markdown", "value": "\n  Division of two `int` values. Same as the division from `Pervasives`.\n\n  ```res example\n  open Belt.Int\n  Js.log(4 / 2 === 2); /* true */\n  ```\n"}
-  }, {
     "label": "Belt.Int.toString",
     "kind": 12,
     "tags": [],
@@ -272,23 +254,5 @@ Completable: Cpath Value[Belt, Array, reduce](Nolabel, Nolabel, Nolabel)->
     "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"}
-  }, {
-    "label": "Belt.Int.fromFloat",
-    "kind": 12,
-    "tags": [],
-    "detail": "float => int",
-    "documentation": {"kind": "markdown", "value": "\n  Converts a given `float` to an `int`.\n\n  ```res example\n  Js.log(Belt.Int.fromFloat(1.0) === 1) /* true */\n  ```\n"}
-  }, {
-    "label": "Belt.Int.-",
-    "kind": 12,
-    "tags": [],
-    "detail": "(int, int) => int",
-    "documentation": {"kind": "markdown", "value": "\n  Subtraction of two `int` values. Same as the subtraction from `Pervasives`.\n\n  ```res example\n  open Belt.Int\n  Js.log(2 - 1 === 1) /* true */\n  ```\n"}
-  }, {
-    "label": "Belt.Int.+",
-    "kind": 12,
-    "tags": [],
-    "detail": "(int, int) => int",
-    "documentation": {"kind": "markdown", "value": "\n  Addition of two `int` values. Same as the addition from `Pervasives`.\n\n  ```res example\n  open Belt.Int\n  Js.log(2 + 2 === 4) /* true */\n  ```\n"}
   }]
 

From 89e1f57222cac3fa41e0858a934522b552cd075c Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Thu, 22 Dec 2022 13:18:54 +0100
Subject: [PATCH 14/14] get rid of redundant cmt lookup

---
 analysis/src/Commands.ml          |  6 ++--
 analysis/src/CompletionBackEnd.ml | 47 +++++++++++++++----------------
 analysis/src/Hover.ml             |  7 +++--
 analysis/src/SignatureHelp.ml     |  7 +++--
 4 files changed, 34 insertions(+), 33 deletions(-)

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 e26a6f805..2b588784a 100644
--- a/analysis/src/CompletionBackEnd.ml
+++ b/analysis/src/CompletionBackEnd.ml
@@ -1157,19 +1157,17 @@ let completionsGetTypeEnv = function
   | {Completion.kind = Field ({typ}, _); env} :: _ -> Some (typ, env)
   | _ -> None
 
-let findReturnTypeOfFunctionAtLoc loc ~(env : QueryEnv.t) ~package ~debug =
-  match Cmt.loadFullCmtFromPath ~path:(env.file.uri |> Uri.toPath) with
-  | None -> None
-  | Some full -> (
-    match References.getLocItem ~full ~pos:(loc |> Loc.end_) ~debug with
-    | Some {locType = Typed (_, typExpr, _)} -> (
-      match extractFunctionType ~env ~package typExpr with
-      | args, tRet when args <> [] -> Some tRet
-      | _ -> None)
+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 ~package ~opens ~rawOpens ~allFiles ~pos
-    ~env ~exact ~scope (contextPath : Completable.contextPath) =
+let rec getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
+    ~exact ~scope (contextPath : Completable.contextPath) =
+  let package = full.package in
   match contextPath with
   | CPString ->
     [
@@ -1192,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) -> (
@@ -1238,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) -> (
@@ -1261,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) -> (
@@ -1289,8 +1287,8 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
   | 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) -> (
@@ -1302,7 +1300,7 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
         match typ with
         | {Types.desc = Tvar _} -> (
           match
-            findReturnTypeOfFunctionAtLoc lhsLoc ~env ~package ~debug:false
+            findReturnTypeOfFunctionAtLoc lhsLoc ~env ~full ~debug:false
           with
           | None -> typ
           | Some typFromLoc -> typFromLoc)
@@ -1443,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
@@ -1458,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
@@ -1808,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/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/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 )))