diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml index b7240a297..10463e787 100644 --- a/analysis/src/CompletionBackEnd.ml +++ b/analysis/src/CompletionBackEnd.ml @@ -1282,7 +1282,7 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos ~env ~exact:true ~scope |> completionsGetTypeEnv with - | Some (typ, _envNotUsed) -> ( + | Some (typ, envFromCompletionItem) -> ( let { arrayModulePath; optionModulePath; @@ -1295,30 +1295,28 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos } = package.builtInCompletionModules in - let getModulePath path = - let rec loop (path : Path.t) = - match path with - | Pident id -> [Ident.name id] - | Pdot (p, s, _) -> s :: loop p - | Papply _ -> [] - in + let getBuiltinTypePath path = + match path with + | Path.Pident id when Ident.name id = "array" -> Some arrayModulePath + | Path.Pident id when Ident.name id = "option" -> Some optionModulePath + | Path.Pident id when Ident.name id = "string" -> Some stringModulePath + | Path.Pident id when Ident.name id = "int" -> Some intModulePath + | Path.Pident id when Ident.name id = "float" -> Some floatModulePath + | Path.Pident id when Ident.name id = "promise" -> + Some promiseModulePath + | Path.Pident id when Ident.name id = "list" -> Some listModulePath + | Path.Pident id when Ident.name id = "result" -> Some resultModulePath + | Path.Pident id when Ident.name id = "lazy_t" -> Some ["Lazy"] + | Path.Pident id when Ident.name id = "char" -> Some ["Char"] + | _ -> None + in + let rec expandPath (path : Path.t) = match path with - | Path.Pident id when Ident.name id = "array" -> arrayModulePath - | Path.Pident id when Ident.name id = "option" -> optionModulePath - | Path.Pident id when Ident.name id = "string" -> stringModulePath - | Path.Pident id when Ident.name id = "int" -> intModulePath - | Path.Pident id when Ident.name id = "float" -> floatModulePath - | Path.Pident id when Ident.name id = "promise" -> promiseModulePath - | Path.Pident id when Ident.name id = "list" -> listModulePath - | Path.Pident id when Ident.name id = "result" -> resultModulePath - | Path.Pident id when Ident.name id = "lazy_t" -> ["Lazy"] - | Path.Pident id when Ident.name id = "char" -> ["Char"] - | _ -> ( - match loop path with - | _ :: rest -> List.rev rest - | [] -> []) + | Pident id -> [Ident.name id] + | Pdot (p, s, _) -> s :: expandPath p + | Papply _ -> [] in - let getConstrPath typ = + let getTypePath typ = match typ.Types.desc with | Tconstr (path, _typeArgs, _) | Tlink {desc = Tconstr (path, _typeArgs, _)} @@ -1327,12 +1325,6 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos Some path | _ -> None in - let fromType typ = - match getConstrPath typ with - | None -> None - | Some path -> Some (getModulePath path) - in - let lhsPath = fromType typ in let rec removeRawOpen rawOpen modulePath = match (rawOpen, modulePath) with | [_], _ -> Some modulePath @@ -1349,33 +1341,54 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos | Some mp -> mp) | [] -> modulePath in - match lhsPath with - | Some modulePath -> ( - match modulePath with - | _ :: _ -> - let modulePathMinusOpens = - modulePath - |> removeRawOpens package.opens - |> removeRawOpens rawOpens |> String.concat "." - in - let completionName name = - if modulePathMinusOpens = "" then name - else modulePathMinusOpens ^ "." ^ name - in - let completions = - modulePath @ [funNamePrefix] - |> getCompletionsForPath ~completionContext:Value ~exact:false - ~package ~opens ~allFiles ~pos ~env ~scope - in - completions - |> List.map (fun (completion : Completion.t) -> - { - completion with - name = completionName completion.name; - env - (* Restore original env for the completion after x->foo()... *); - }) - | [] -> []) + let completionPath = + match getTypePath typ with + | Some typePath -> ( + match getBuiltinTypePath typePath with + | Some path -> Some path + | None -> ( + match expandPath typePath with + | _ :: rest when rest <> [] -> + (* Assume a non-empty type path is coming from the compiler and + can be used as-is. *) + Some (List.rev rest) + | _ -> + (* Get the path from the comletion environment *) + let path = envFromCompletionItem.path in + if path = [] then None + else + let pathFromEnv = + if env.file.moduleName = envFromCompletionItem.file.moduleName + then path + else envFromCompletionItem.file.moduleName :: path + in + Some pathFromEnv)) + | None -> None + in + match completionPath with + | Some completionPath -> + let completionPathMinusOpens = + completionPath + |> removeRawOpens package.opens + |> removeRawOpens rawOpens |> String.concat "." + in + let completionName name = + if completionPathMinusOpens = "" then name + else completionPathMinusOpens ^ "." ^ name + in + let completions = + completionPath @ [funNamePrefix] + |> getCompletionsForPath ~completionContext:Value ~exact:false + ~package ~opens ~allFiles ~pos ~env ~scope + in + completions + |> List.map (fun (completion : Completion.t) -> + { + completion with + name = completionName completion.name; + env + (* Restore original env for the completion after x->foo()... *); + }) | None -> []) | None -> []) diff --git a/analysis/src/CompletionFrontEnd.ml b/analysis/src/CompletionFrontEnd.ml index bce92250b..d7f12cac5 100644 --- a/analysis/src/CompletionFrontEnd.ml +++ b/analysis/src/CompletionFrontEnd.ml @@ -157,6 +157,46 @@ let rec exprToContextPath (e : Parsetree.expression) = | Some contexPath -> Some (CPApply (contexPath, args |> List.map fst))) | _ -> None +let completePipeChain ~(lhs : Parsetree.expression) = + (* Complete the end of pipe chains by reconstructing the pipe chain as a single pipe, + so it can be completed. + Example: + someArray->Js.Array2.filter(v => v > 10)->Js.Array2.map(v => v + 2)-> + will complete as: + Js.Array2.map(someArray->Js.Array2.filter(v => v > 10), v => v + 2)-> + *) + match lhs.pexp_desc with + (* When the left side of the pipe we're completing is a function application. + Example: someArray->Js.Array2.map(v => v + 2)-> *) + | Pexp_apply + ( {pexp_desc = Pexp_ident {txt = Lident "|."}}, + [ + (_, lhs); + (_, {pexp_desc = Pexp_apply (d, args); pexp_loc; pexp_attributes}); + ] ) -> + exprToContextPath + { + pexp_desc = Pexp_apply (d, (Nolabel, lhs) :: args); + pexp_loc; + pexp_attributes; + } + (* When the left side of the pipe we're completing is an identifier application. + Example: someArray->filterAllTheGoodStuff-> *) + | Pexp_apply + ( {pexp_desc = Pexp_ident {txt = Lident "|."}}, + [(_, lhs); (_, {pexp_desc = Pexp_ident id; pexp_loc; pexp_attributes})] + ) -> + exprToContextPath + { + pexp_desc = + Pexp_apply + ( {pexp_desc = Pexp_ident id; pexp_loc; pexp_attributes}, + [(Nolabel, lhs)] ); + pexp_loc; + pexp_attributes; + } + | _ -> None + let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text = let offsetNoWhite = skipWhite text (offset - 1) in let posNoWhite = @@ -392,11 +432,16 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text = (Loc.toString expr.pexp_loc) in let setPipeResult ~(lhs : Parsetree.expression) ~id = - match exprToContextPath lhs with + match completePipeChain ~lhs with + | None -> ( + match exprToContextPath lhs with + | Some pipe -> + setResult (Cpath (CPPipe (pipe, id))); + true + | None -> false) | Some pipe -> setResult (Cpath (CPPipe (pipe, id))); true - | None -> false in match expr.pexp_desc with | Pexp_apply diff --git a/analysis/src/ProcessCmt.ml b/analysis/src/ProcessCmt.ml index b005cf2fe..dab690758 100644 --- a/analysis/src/ProcessCmt.ml +++ b/analysis/src/ProcessCmt.ml @@ -104,10 +104,11 @@ let rec forTypeSignatureItem ~(env : SharedTypes.Env.t) ~(exported : Exported.t) in [{Module.kind = Type (declared.item, recStatus); name = declared.name.txt}] | Sig_module (ident, {md_type; md_attributes; md_loc}, _) -> + let name = Ident.name ident in let declared = addDeclared ~extent:md_loc - ~item:(forTypeModule env md_type) - ~name:(Location.mkloc (Ident.name ident) md_loc) + ~item:(forTypeModule ~name ~env md_type) + ~name:(Location.mkloc name md_loc) ~stamp:(Ident.binding_time ident) ~env md_attributes (Exported.add exported Exported.Module) Stamps.addModule @@ -115,22 +116,22 @@ let rec forTypeSignatureItem ~(env : SharedTypes.Env.t) ~(exported : Exported.t) [{Module.kind = Module declared.item; name = declared.name.txt}] | _ -> [] -and forTypeSignature env signature = +and forTypeSignature ~name ~env signature = let exported = Exported.init () in let items = List.fold_right (fun item items -> forTypeSignatureItem ~env ~exported item @ items) signature [] in - {Module.docstring = []; exported; items} + {Module.name; docstring = []; exported; items} -and forTypeModule env moduleType = +and forTypeModule ~name ~env moduleType = match moduleType with | Types.Mty_ident path -> Ident path | Mty_alias (_ (* 402 *), path) -> Ident path - | Mty_signature signature -> Structure (forTypeSignature env signature) + | Mty_signature signature -> Structure (forTypeSignature ~name ~env signature) | Mty_functor (_argIdent, _argType, resultType) -> - forTypeModule env resultType + forTypeModule ~name ~env resultType let getModuleTypePath mod_desc = match mod_desc with @@ -249,7 +250,11 @@ let rec forSignatureItem ~env ~(exported : Exported.t) decl |> forTypeDeclaration ~env ~exported ~recStatus) | Tsig_module {md_id; md_attributes; md_loc; md_name = name; md_type = {mty_type}} -> - let item = forTypeModule (env |> Env.addModule ~name:name.txt) mty_type in + let item = + forTypeModule ~name:name.txt + ~env:(env |> Env.addModule ~name:name.txt) + mty_type + in let declared = addDeclared ~item ~name ~extent:md_loc ~stamp:(Ident.binding_time md_id) ~env md_attributes @@ -279,7 +284,7 @@ let rec forSignatureItem ~env ~(exported : Exported.t) (* TODO: process other things here *) | _ -> [] -let forSignature ~env sigItems = +let forSignature ~name ~env sigItems = let exported = Exported.init () in let items = sigItems |> List.map (forSignatureItem ~env ~exported) |> List.flatten @@ -294,13 +299,13 @@ let forSignature ~env sigItems = | None -> [] | Some d -> [d] in - {Module.docstring; exported; items} + {Module.name; docstring; exported; items} -let forTreeModuleType ~env {Typedtree.mty_desc} = +let forTreeModuleType ~name ~env {Typedtree.mty_desc} = match mty_desc with | Tmty_ident _ -> None | Tmty_signature {sig_items} -> - let contents = forSignature ~env sig_items in + let contents = forSignature ~name ~env sig_items in Some (Module.Structure contents) | _ -> None @@ -352,7 +357,7 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = (String.length name.txt >= 6 && (String.sub name.txt 0 6 = "local_") [@doesNotRaise]) (* %%private generates a dummy module called local_... *) -> - let item = forModule env mod_desc name.txt in + let item = forModule ~env mod_desc name.txt in let declared = addDeclared ~item ~name ~extent:mb_loc ~stamp:(Ident.binding_time mb_id) ~env mb_attributes @@ -375,7 +380,7 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = mtd_loc; } -> let env = env |> Env.addModuleType ~name:name.txt in - let modTypeItem = forTypeModule env modType in + let modTypeItem = forTypeModule ~name:name.txt ~env modType in let declared = addDeclared ~item:modTypeItem ~name ~extent:mtd_loc ~stamp:(Ident.binding_time mtd_id) @@ -418,18 +423,18 @@ let rec forStructureItem ~env ~(exported : Exported.t) item = decl |> forTypeDeclaration ~env ~exported ~recStatus) | _ -> [] -and forModule env mod_desc moduleName = +and forModule ~env mod_desc moduleName = match mod_desc with | Tmod_ident (path, _lident) -> Ident path | Tmod_structure structure -> let env = env |> Env.addModule ~name:moduleName in - let contents = forStructure ~env structure.str_items in + let contents = forStructure ~name:moduleName ~env structure.str_items in Structure contents | Tmod_functor (ident, argName, maybeType, resultExpr) -> (match maybeType with | None -> () | Some t -> ( - match forTreeModuleType ~env t with + match forTreeModuleType ~name:argName.txt ~env t with | None -> () | Some kind -> let stamp = Ident.binding_time ident in @@ -438,20 +443,20 @@ and forModule env mod_desc moduleName = ~extent:t.Typedtree.mty_loc ~stamp ~modulePath:NotVisible false [] in Stamps.addModule env.stamps stamp declared)); - forModule env resultExpr.mod_desc moduleName + forModule ~env resultExpr.mod_desc moduleName | Tmod_apply (functor_, _arg, _coercion) -> - forModule env functor_.mod_desc moduleName + forModule ~env functor_.mod_desc moduleName | Tmod_unpack (_expr, moduleType) -> let env = env |> Env.addModule ~name:moduleName in - forTypeModule env moduleType + forTypeModule ~name:moduleName ~env moduleType | Tmod_constraint (expr, typ, _constraint, _coercion) -> (* TODO do this better I think *) - let modKind = forModule env expr.mod_desc moduleName in + let modKind = forModule ~env expr.mod_desc moduleName in let env = env |> Env.addModule ~name:moduleName in - let modTypeKind = forTypeModule env typ in + let modTypeKind = forTypeModule ~name:moduleName ~env typ in Constraint (modKind, modTypeKind) -and forStructure ~env strItems = +and forStructure ~name ~env strItems = let exported = Exported.init () in let items = List.fold_right @@ -468,7 +473,7 @@ and forStructure ~env strItems = | None -> [] | Some d -> [d] in - {docstring; exported; items} + {Module.name; docstring; exported; items} let fileForCmtInfos ~moduleName ~uri ({cmt_modname; cmt_annots} : Cmt_format.cmt_infos) = @@ -486,7 +491,7 @@ let fileForCmtInfos ~moduleName ~uri | _ -> None) |> List.concat in - let structure = forStructure ~env items in + let structure = forStructure ~name:moduleName ~env items in {File.uri; moduleName = cmt_modname; stamps = env.stamps; structure} | Partial_interface parts -> let items = @@ -498,13 +503,13 @@ let fileForCmtInfos ~moduleName ~uri | _ -> None) |> List.concat in - let structure = forSignature ~env items in + let structure = forSignature ~name:moduleName ~env items in {uri; moduleName = cmt_modname; stamps = env.stamps; structure} | Implementation structure -> - let structure = forStructure ~env structure.str_items in + let structure = forStructure ~name:moduleName ~env structure.str_items in {uri; moduleName = cmt_modname; stamps = env.stamps; structure} | Interface signature -> - let structure = forSignature ~env signature.sig_items in + let structure = forSignature ~name:moduleName ~env signature.sig_items in {uri; moduleName = cmt_modname; stamps = env.stamps; structure} | _ -> File.create moduleName uri diff --git a/analysis/src/ResolvePath.ml b/analysis/src/ResolvePath.ml index dc930a7e7..877e273fe 100644 --- a/analysis/src/ResolvePath.ml +++ b/analysis/src/ResolvePath.ml @@ -46,7 +46,8 @@ and resolvePathInner ~(env : QueryEnv.t) ~path = and findInModule ~(env : QueryEnv.t) module_ path = match module_ with - | Structure {exported} -> resolvePathInner ~env:{env with exported} ~path + | Structure structure -> + resolvePathInner ~env:(QueryEnv.enterStructure env structure) ~path | Constraint (_, module1) -> findInModule ~env module1 path | Ident modulePath -> ( let stamp, moduleName, fullPath = joinPaths modulePath path in diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml index 549c5ea32..e5ee97e9f 100644 --- a/analysis/src/SharedTypes.ml +++ b/analysis/src/SharedTypes.ml @@ -105,6 +105,7 @@ module Module = struct and item = {kind: kind; name: string} and structure = { + name: string; docstring: string list; exported: Exported.t; items: item list; @@ -226,14 +227,26 @@ module File = struct uri; stamps = Stamps.init (); moduleName; - structure = {docstring = []; exported = Exported.init (); items = []}; + structure = + { + name = moduleName; + docstring = []; + exported = Exported.init (); + items = []; + }; } end -module QueryEnv = struct - type t = {file: File.t; exported: Exported.t} +module QueryEnv : sig + type t = private {file: File.t; exported: Exported.t; path: path} + val fromFile : File.t -> t + val enterStructure : t -> Module.structure -> t +end = struct + type t = {file: File.t; exported: Exported.t; path: path} - let fromFile file = {file; exported = file.structure.exported} + let fromFile file = {file; exported = file.structure.exported; path = []} + let enterStructure env (structure : Module.structure) = + {env with exported = structure.exported; path = structure.name :: env.path} end module Completion = struct diff --git a/analysis/tests/src/CompletionPipeChain.res b/analysis/tests/src/CompletionPipeChain.res new file mode 100644 index 000000000..59c1af258 --- /dev/null +++ b/analysis/tests/src/CompletionPipeChain.res @@ -0,0 +1,60 @@ +module Integer: { + type t + let increment: (t, int) => t + let decrement: (t, int => int) => t + let make: int => t + let toInt: t => int +} = { + type t = int + let increment = (t, num) => t + num + let decrement = (t, decrementer) => decrementer(t) + let make = t => t + let toInt = t => t +} + +module SuperFloat: { + type t + let fromInteger: Integer.t => t + let toInteger: t => Integer.t +} = { + type t = float + let fromInteger = t => t->Integer.toInt->Belt.Float.fromInt + let toInteger = t => t->Belt.Float.toInt->Integer.make +} + +let toFlt = i => i->SuperFloat.fromInteger +let int = Integer.make(1) +let f = int->Integer.increment(2) +// let _ = int-> +// ^com + +// let _ = int->toFlt-> +// ^com + +// let _ = int->Integer.increment(2)-> +// ^com + +// let _ = Integer.increment(int, 2)-> +// ^com + +// let _ = int->Integer.decrement(t => t - 1)-> +// ^com + +// let _ = int->Integer.increment(2)->Integer.decrement(t => t - 1)-> +// ^com + +// let _ = int->Integer.increment(2)->SuperFloat.fromInteger-> +// ^com + +// let _ = int->Integer.increment(2)->SuperFloat.fromInteger->t +// ^com + +// let _ = int->Integer.increment(2)->Integer.toInt->CompletionSupport.Test.make-> +// ^com + +// let _ = CompletionSupport.Test.make(1)->CompletionSupport.Test.addSelf(2)-> +// ^com + +let _ = [123]->Js.Array2.forEach(v => Js.log(v)) +// -> +// ^com diff --git a/analysis/tests/src/CompletionSupport.res b/analysis/tests/src/CompletionSupport.res new file mode 100644 index 000000000..371ca57b1 --- /dev/null +++ b/analysis/tests/src/CompletionSupport.res @@ -0,0 +1,6 @@ +module Test = { + type t = {name: int} + let add = (ax: t) => ax.name + 1 + let addSelf = (ax: t) => {name: ax.name + 1} + let make = (name: int): t => {name: name} +} diff --git a/analysis/tests/src/expected/CompletionPipeChain.res.txt b/analysis/tests/src/expected/CompletionPipeChain.res.txt new file mode 100644 index 000000000..fe947a437 --- /dev/null +++ b/analysis/tests/src/expected/CompletionPipeChain.res.txt @@ -0,0 +1,241 @@ +Complete src/CompletionPipeChain.res 27:16 +posCursor:[27:16] posNoWhite:[27:15] Found expr:[27:11->0:-1] +Completable: Cpath Value[int]-> +[{ + "label": "Integer.toInt", + "kind": 12, + "tags": [], + "detail": "t => int", + "documentation": null + }, { + "label": "Integer.increment", + "kind": 12, + "tags": [], + "detail": "(t, int) => t", + "documentation": null + }, { + "label": "Integer.decrement", + "kind": 12, + "tags": [], + "detail": "(t, int => int) => t", + "documentation": null + }, { + "label": "Integer.make", + "kind": 12, + "tags": [], + "detail": "int => t", + "documentation": null + }] + +Complete src/CompletionPipeChain.res 30:23 +posCursor:[30:23] posNoWhite:[30:22] Found expr:[30:11->0:-1] +Completable: Cpath Value[toFlt](Nolabel)-> +[{ + "label": "SuperFloat.fromInteger", + "kind": 12, + "tags": [], + "detail": "Integer.t => t", + "documentation": null + }, { + "label": "SuperFloat.toInteger", + "kind": 12, + "tags": [], + "detail": "t => Integer.t", + "documentation": null + }] + +Complete src/CompletionPipeChain.res 33:38 +posCursor:[33:38] posNoWhite:[33:37] Found expr:[33:11->0:-1] +Completable: Cpath Value[Integer, increment](Nolabel, Nolabel)-> +[{ + "label": "Integer.toInt", + "kind": 12, + "tags": [], + "detail": "t => int", + "documentation": null + }, { + "label": "Integer.increment", + "kind": 12, + "tags": [], + "detail": "(t, int) => t", + "documentation": null + }, { + "label": "Integer.decrement", + "kind": 12, + "tags": [], + "detail": "(t, int => int) => t", + "documentation": null + }, { + "label": "Integer.make", + "kind": 12, + "tags": [], + "detail": "int => t", + "documentation": null + }] + +Complete src/CompletionPipeChain.res 36:38 +posCursor:[36:38] posNoWhite:[36:37] Found expr:[36:11->0:-1] +Completable: Cpath Value[Integer, increment](Nolabel, Nolabel)-> +[{ + "label": "Integer.toInt", + "kind": 12, + "tags": [], + "detail": "t => int", + "documentation": null + }, { + "label": "Integer.increment", + "kind": 12, + "tags": [], + "detail": "(t, int) => t", + "documentation": null + }, { + "label": "Integer.decrement", + "kind": 12, + "tags": [], + "detail": "(t, int => int) => t", + "documentation": null + }, { + "label": "Integer.make", + "kind": 12, + "tags": [], + "detail": "int => t", + "documentation": null + }] + +Complete src/CompletionPipeChain.res 39:47 +posCursor:[39:47] posNoWhite:[39:46] Found expr:[39:11->0:-1] +Completable: Cpath Value[Integer, decrement](Nolabel, Nolabel)-> +[{ + "label": "Integer.toInt", + "kind": 12, + "tags": [], + "detail": "t => int", + "documentation": null + }, { + "label": "Integer.increment", + "kind": 12, + "tags": [], + "detail": "(t, int) => t", + "documentation": null + }, { + "label": "Integer.decrement", + "kind": 12, + "tags": [], + "detail": "(t, int => int) => t", + "documentation": null + }, { + "label": "Integer.make", + "kind": 12, + "tags": [], + "detail": "int => t", + "documentation": null + }] + +Complete src/CompletionPipeChain.res 42:69 +posCursor:[42:69] posNoWhite:[42:68] Found expr:[42:11->0:-1] +Completable: Cpath Value[Integer, decrement](Nolabel, Nolabel)-> +[{ + "label": "Integer.toInt", + "kind": 12, + "tags": [], + "detail": "t => int", + "documentation": null + }, { + "label": "Integer.increment", + "kind": 12, + "tags": [], + "detail": "(t, int) => t", + "documentation": null + }, { + "label": "Integer.decrement", + "kind": 12, + "tags": [], + "detail": "(t, int => int) => t", + "documentation": null + }, { + "label": "Integer.make", + "kind": 12, + "tags": [], + "detail": "int => t", + "documentation": null + }] + +Complete src/CompletionPipeChain.res 45:62 +posCursor:[45:62] posNoWhite:[45:61] Found expr:[45:11->0:-1] +Completable: Cpath Value[SuperFloat, fromInteger](Nolabel)-> +[{ + "label": "SuperFloat.fromInteger", + "kind": 12, + "tags": [], + "detail": "Integer.t => t", + "documentation": null + }, { + "label": "SuperFloat.toInteger", + "kind": 12, + "tags": [], + "detail": "t => Integer.t", + "documentation": null + }] + +Complete src/CompletionPipeChain.res 48:63 +posCursor:[48:63] posNoWhite:[48:62] Found expr:[48:11->48:63] +Completable: Cpath Value[SuperFloat, fromInteger](Nolabel)->t +[{ + "label": "SuperFloat.toInteger", + "kind": 12, + "tags": [], + "detail": "t => Integer.t", + "documentation": null + }] + +Complete src/CompletionPipeChain.res 51:82 +posCursor:[51:82] posNoWhite:[51:81] Found expr:[51:11->0:-1] +Completable: Cpath Value[CompletionSupport, Test, make](Nolabel)-> +[{ + "label": "CompletionSupport.Test.add", + "kind": 12, + "tags": [], + "detail": "t => int", + "documentation": null + }, { + "label": "CompletionSupport.Test.addSelf", + "kind": 12, + "tags": [], + "detail": "t => t", + "documentation": null + }, { + "label": "CompletionSupport.Test.make", + "kind": 12, + "tags": [], + "detail": "int => t", + "documentation": null + }] + +Complete src/CompletionPipeChain.res 54:78 +posCursor:[54:78] posNoWhite:[54:77] Found expr:[54:11->0:-1] +Completable: Cpath Value[CompletionSupport, Test, addSelf](Nolabel, Nolabel)-> +[{ + "label": "CompletionSupport.Test.add", + "kind": 12, + "tags": [], + "detail": "t => int", + "documentation": null + }, { + "label": "CompletionSupport.Test.addSelf", + "kind": 12, + "tags": [], + "detail": "t => t", + "documentation": null + }, { + "label": "CompletionSupport.Test.make", + "kind": 12, + "tags": [], + "detail": "int => t", + "documentation": null + }] + +Complete src/CompletionPipeChain.res 58:5 +posCursor:[58:5] posNoWhite:[58:4] Found expr:[57:8->0:-1] +Completable: Cpath Value[Js, Array2, forEach](Nolabel, Nolabel)-> +[] + diff --git a/analysis/tests/src/expected/CompletionSupport.res.txt b/analysis/tests/src/expected/CompletionSupport.res.txt new file mode 100644 index 000000000..e69de29bb