diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml index 61acb9d08..2db69a7f3 100644 --- a/analysis/src/CompletionBackEnd.ml +++ b/analysis/src/CompletionBackEnd.ml @@ -373,6 +373,26 @@ let getItemsFromOpens ~opens ~localTables ~prefix ~exact ~completionContext = completionsFromThisOpen @ results) [] +let builtinTypes = + [ + ("string", "string"); + ("int", "int"); + ("float", "float"); + ("bool", "bool"); + ("option", "option<${1:_}>"); + ("array", "array<${1:_}>"); + ("promise", "promise<${1:_}>"); + ("result", "result<${1:_}, ${2:_}>"); + ] + +let getTypesFromBuiltins ~env ~prefix ~exact = + builtinTypes + |> List.filter (fun (typeName, _) -> + if exact then typeName == prefix else Utils.startsWith typeName prefix) + |> List.map (fun (typeName, template) -> + Completion.createWithSnippet ~name:typeName ~insertText:template ~env + ~kind:(Completion.Label typeName) ()) + let findLocalCompletionsForValuesAndConstructors ~(localTables : LocalTables.t) ~env ~prefix ~exact ~opens ~scope = localTables |> LocalTables.populateValues ~env; @@ -442,6 +462,7 @@ let findLocalCompletionsForTypes ~(localTables : LocalTables.t) ~env ~prefix let valuesFromOpens = getItemsFromOpens ~opens ~localTables ~prefix ~exact ~completionContext:Type in + let typesFromBuiltins = getTypesFromBuiltins ~env ~prefix ~exact in scope |> Scope.iterTypesAfterFirstOpen @@ -449,7 +470,7 @@ let findLocalCompletionsForTypes ~(localTables : LocalTables.t) ~env ~prefix scope |> Scope.iterModulesAfterFirstOpen (processLocalModule ~prefix ~exact ~env ~localTables); - List.rev_append localTables.resultRev valuesFromOpens + List.rev_append localTables.resultRev (valuesFromOpens @ typesFromBuiltins) let findLocalCompletionsForModules ~(localTables : LocalTables.t) ~env ~prefix ~exact ~opens ~scope = @@ -745,6 +766,7 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact | Some (Tpromise (env, typ), _env) -> [Completion.create "dummy" ~env ~kind:(Completion.Value typ)] | _ -> []) + | CPId ([], Type) -> getTypesFromBuiltins ~env ~prefix:"" ~exact | CPId (path, completionContext) -> path |> getCompletionsForPath ~debug ~package ~opens ~full ~pos ~exact diff --git a/analysis/src/CompletionFrontEnd.ml b/analysis/src/CompletionFrontEnd.ml index 70ce8eda5..caecf6d4e 100644 --- a/analysis/src/CompletionFrontEnd.ml +++ b/analysis/src/CompletionFrontEnd.ml @@ -819,6 +819,10 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor in typedCompletionExpr expr; match expr.pexp_desc with + | Pexp_coerce (_e, _, typ) + when expr.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor + && Utils.isTypeHole typ -> + setResult (Cpath (CPId ([], Type))) | Pexp_match (expr, cases) when cases <> [] -> let ctxPath = exprToContextPath expr in let oldCtxPath = !currentCtxPath in diff --git a/analysis/src/Utils.ml b/analysis/src/Utils.ml index e548457f2..903e1ded6 100644 --- a/analysis/src/Utils.ml +++ b/analysis/src/Utils.ml @@ -216,3 +216,8 @@ let rec lastElements list = let lowercaseFirstChar s = if String.length s = 0 then s else String.mapi (fun i c -> if i = 0 then Char.lowercase_ascii c else c) s + +let isTypeHole typ = + match typ.Parsetree.ptyp_desc with + | Ptyp_extension ({txt = "rescript.typehole"}, _) -> true + | _ -> false diff --git a/analysis/tests/src/Completion.res b/analysis/tests/src/Completion.res index 153e6d237..fcb046d80 100644 --- a/analysis/tests/src/Completion.res +++ b/analysis/tests/src/Completion.res @@ -462,3 +462,9 @@ type withUncurried = { // let f: withUncurried = {fn: } // ^com + +// let a = (fff :> ) +// ^com + +// let a = (fff :> boo) +// ^com diff --git a/analysis/tests/src/expected/Completion.res.txt b/analysis/tests/src/expected/Completion.res.txt index aef3b28be..76192e18d 100644 --- a/analysis/tests/src/expected/Completion.res.txt +++ b/analysis/tests/src/expected/Completion.res.txt @@ -1323,6 +1323,14 @@ Path s "tags": [], "detail": "type someLocalVariant = SomeLocalVariantItem", "documentation": null + }, { + "label": "string", + "kind": 4, + "tags": [], + "detail": "string", + "documentation": null, + "insertText": "string", + "insertTextFormat": 2 }] Complete src/Completion.res 291:30 @@ -1950,8 +1958,8 @@ Path red }] Complete src/Completion.res 405:22 -posCursor:[405:22] posNoWhite:[405:21] Found expr:[405:11->465:0] -Pexp_apply ...__ghost__[0:-1->0:-1] (...[405:11->423:17], ...[428:0->465:0]) +posCursor:[405:22] posNoWhite:[405:21] Found expr:[405:11->471:0] +Pexp_apply ...__ghost__[0:-1->0:-1] (...[405:11->423:17], ...[428:0->471:0]) posCursor:[405:22] posNoWhite:[405:21] Found expr:[405:11->423:17] Pexp_apply ...__ghost__[0:-1->0:-1] (...[405:11->405:19], ...[405:21->423:17]) posCursor:[405:22] posNoWhite:[405:21] Found expr:[405:21->423:17] @@ -2206,3 +2214,96 @@ Path withUncurried "insertTextFormat": 2 }] +Complete src/Completion.res 465:19 +XXX Not found! +Completable: Cpath Type[] +Raw opens: 2 Shadow.B.place holder ... Shadow.A.place holder +Package opens Pervasives.JsxModules.place holder +Resolved opens 3 Completion.res Completion.res pervasives +ContextPath Type[] +[{ + "label": "string", + "kind": 4, + "tags": [], + "detail": "string", + "documentation": null, + "insertText": "string", + "insertTextFormat": 2 + }, { + "label": "int", + "kind": 4, + "tags": [], + "detail": "int", + "documentation": null, + "insertText": "int", + "insertTextFormat": 2 + }, { + "label": "float", + "kind": 4, + "tags": [], + "detail": "float", + "documentation": null, + "insertText": "float", + "insertTextFormat": 2 + }, { + "label": "bool", + "kind": 4, + "tags": [], + "detail": "bool", + "documentation": null, + "insertText": "bool", + "insertTextFormat": 2 + }, { + "label": "option", + "kind": 4, + "tags": [], + "detail": "option", + "documentation": null, + "insertText": "option<${1:_}>", + "insertTextFormat": 2 + }, { + "label": "array", + "kind": 4, + "tags": [], + "detail": "array", + "documentation": null, + "insertText": "array<${1:_}>", + "insertTextFormat": 2 + }, { + "label": "promise", + "kind": 4, + "tags": [], + "detail": "promise", + "documentation": null, + "insertText": "promise<${1:_}>", + "insertTextFormat": 2 + }, { + "label": "result", + "kind": 4, + "tags": [], + "detail": "result", + "documentation": null, + "insertText": "result<${1:_}, ${2:_}>", + "insertTextFormat": 2 + }] + +Complete src/Completion.res 468:22 +posCursor:[468:22] posNoWhite:[468:21] Found expr:[468:12->468:22] +posCursor:[468:22] posNoWhite:[468:21] Found type:[468:19->468:22] +Ptyp_constr boo:[468:19->468:22] +Completable: Cpath Type[boo] +Raw opens: 2 Shadow.B.place holder ... Shadow.A.place holder +Package opens Pervasives.JsxModules.place holder +Resolved opens 3 Completion.res Completion.res pervasives +ContextPath Type[boo] +Path boo +[{ + "label": "bool", + "kind": 4, + "tags": [], + "detail": "bool", + "documentation": null, + "insertText": "bool", + "insertTextFormat": 2 + }] +