From 18ed5ac0eaf00d85e9443086383434073c2ccba1 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sat, 19 Aug 2023 21:31:45 +0200 Subject: [PATCH 1/2] make completion engine understand await --- analysis/src/CompletionBackEnd.ml | 16 +++++++++ analysis/src/CompletionFrontEnd.ml | 11 +++++- analysis/src/SharedTypes.ml | 3 ++ analysis/src/TypeUtils.ml | 6 ++++ analysis/tests/src/CompletionPattern.res | 5 +++ .../src/expected/CompletionPattern.res.txt | 35 +++++++++++++++++++ 6 files changed, 75 insertions(+), 1 deletion(-) diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml index 2888a37b1..08a9eabe8 100644 --- a/analysis/src/CompletionBackEnd.ml +++ b/analysis/src/CompletionBackEnd.ml @@ -735,6 +735,21 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact ~kind: (Completion.ExtractedType (Toption (env, ExtractedType typ), `Type)); ]) + | CPAwait cp -> ( + match + cp + |> getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env + ~exact:true ~scope + |> completionsGetCompletionType ~full + with + | Some (Tpromise (env, TypeExpr typ), _env) -> + [Completion.create "dummy" ~env ~kind:(Completion.Value typ)] + | Some (Tpromise (env, ExtractedType typ), _env) -> + [ + Completion.create "dummy" ~env + ~kind:(Completion.ExtractedType (typ, `Type)); + ] + | _ -> []) | CPId (path, completionContext) -> path |> getCompletionsForPath ~debug ~package ~opens ~full ~pos ~exact @@ -1433,6 +1448,7 @@ let rec completeTypedValue ~full ~prefix ~completionContext ~mode ] ~env; ] + | Tpromise _ -> [] let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable = if debug then diff --git a/analysis/src/CompletionFrontEnd.ml b/analysis/src/CompletionFrontEnd.ml index 261ac735a..3c0cd091e 100644 --- a/analysis/src/CompletionFrontEnd.ml +++ b/analysis/src/CompletionFrontEnd.ml @@ -136,7 +136,7 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor }) | _ -> loop args -let rec exprToContextPath (e : Parsetree.expression) = +let rec exprToContextPathInner (e : Parsetree.expression) = match e.pexp_desc with | Pexp_constant (Pconst_string _) -> Some Completable.CPString | Pexp_constant (Pconst_integer _) -> Some CPInt @@ -199,6 +199,15 @@ let rec exprToContextPath (e : Parsetree.expression) = else None | _ -> None +and exprToContextPath (e : Parsetree.expression) = + match + ( Res_parsetree_viewer.hasAwaitAttribute e.pexp_attributes, + exprToContextPathInner e ) + with + | true, Some ctxPath -> Some (CPAwait ctxPath) + | false, Some ctxPath -> Some ctxPath + | _, None -> None + let completePipeChain (exp : Parsetree.expression) = (* Complete the end of pipe chains by reconstructing the pipe chain as a single pipe, so it can be completed. diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml index 5af4b2b74..54105c4bb 100644 --- a/analysis/src/SharedTypes.ml +++ b/analysis/src/SharedTypes.ml @@ -310,6 +310,7 @@ type innerType = TypeExpr of Types.type_expr | ExtractedType of completionType and completionType = | Tuple of QueryEnv.t * Types.type_expr list * Types.type_expr | Texn of QueryEnv.t + | Tpromise of QueryEnv.t * innerType | Toption of QueryEnv.t * innerType | Tbool of QueryEnv.t | Tarray of QueryEnv.t * innerType @@ -578,6 +579,7 @@ module Completable = struct | CPId of string list * completionContext | CPField of contextPath * string | CPObj of contextPath * string + | CPAwait of contextPath | CPPipe of { contextPath: contextPath; id: string; @@ -631,6 +633,7 @@ module Completable = struct | CPInt -> "int" | CPFloat -> "float" | CPBool -> "bool" + | CPAwait ctxPath -> "await " ^ contextPathToString ctxPath | CPOption ctxPath -> "option<" ^ contextPathToString ctxPath ^ ">" | CPApply (cp, labels) -> contextPathToString cp ^ "(" diff --git a/analysis/src/TypeUtils.ml b/analysis/src/TypeUtils.ml index b0455e4da..0cb30c21f 100644 --- a/analysis/src/TypeUtils.ml +++ b/analysis/src/TypeUtils.ml @@ -115,6 +115,8 @@ let rec extractType ~env ~package (t : Types.type_expr) = | Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> extractType ~env ~package t1 | Tconstr (Path.Pident {name = "option"}, [payloadTypeExpr], _) -> Some (Toption (env, TypeExpr payloadTypeExpr)) + | Tconstr (Path.Pident {name = "promise"}, [payloadTypeExpr], _) -> + Some (Tpromise (env, TypeExpr payloadTypeExpr)) | Tconstr (Path.Pident {name = "array"}, [payloadTypeExpr], _) -> Some (Tarray (env, TypeExpr payloadTypeExpr)) | Tconstr (Path.Pident {name = "bool"}, [], _) -> Some (Tbool env) @@ -595,6 +597,10 @@ let rec extractedTypeToString ?(inner = false) = function "option<" ^ Shared.typeToString innerTyp ^ ">" | Toption (_, ExtractedType innerTyp) -> "option<" ^ extractedTypeToString ~inner:true innerTyp ^ ">" + | Tpromise (_, TypeExpr innerTyp) -> + "promise<" ^ Shared.typeToString innerTyp ^ ">" + | Tpromise (_, ExtractedType innerTyp) -> + "promise<" ^ extractedTypeToString ~inner:true innerTyp ^ ">" | Tvariant {variantDecl; variantName} -> if inner then variantName else Shared.declToString variantName variantDecl | Trecord {definition = `NameOnly name; fields} -> diff --git a/analysis/tests/src/CompletionPattern.res b/analysis/tests/src/CompletionPattern.res index b2280b88c..aae445bb9 100644 --- a/analysis/tests/src/CompletionPattern.res +++ b/analysis/tests/src/CompletionPattern.res @@ -206,3 +206,8 @@ let xn: exn = Obj.magic() // switch xn { | } // ^com + +let getThing = async () => One + +// switch await getThing() { | } +// ^com diff --git a/analysis/tests/src/expected/CompletionPattern.res.txt b/analysis/tests/src/expected/CompletionPattern.res.txt index 3883cc749..d74cfec1a 100644 --- a/analysis/tests/src/expected/CompletionPattern.res.txt +++ b/analysis/tests/src/expected/CompletionPattern.res.txt @@ -1070,3 +1070,38 @@ Path xn "documentation": {"kind": "markdown", "value": "Matches on a JavaScript error. Read more in the [documentation on catching JS exceptions](https://rescript-lang.org/docs/manual/latest/exception#catching-js-exceptions)."} }] +Complete src/CompletionPattern.res 211:30 +XXX Not found! +Completable: Cpattern await Value[getThing](Nolabel) +Package opens Pervasives.JsxModules.place holder +Resolved opens 1 pervasives +ContextPath await Value[getThing](Nolabel) +ContextPath Value[getThing](Nolabel) +ContextPath Value[getThing] +Path getThing +[{ + "label": "One", + "kind": 4, + "tags": [], + "detail": "One\n\ntype someVariant = One | Two(bool) | Three(someRecord, bool)", + "documentation": null, + "insertText": "One", + "insertTextFormat": 2 + }, { + "label": "Two(_)", + "kind": 4, + "tags": [], + "detail": "Two(bool)\n\ntype someVariant = One | Two(bool) | Three(someRecord, bool)", + "documentation": null, + "insertText": "Two(${1:_})", + "insertTextFormat": 2 + }, { + "label": "Three(_, _)", + "kind": 4, + "tags": [], + "detail": "Three(someRecord, bool)\n\ntype someVariant = One | Two(bool) | Three(someRecord, bool)", + "documentation": null, + "insertText": "Three(${1:_}, ${2:_})", + "insertTextFormat": 2 + }] + From 88f4df7516b6ca708d823109fb229c8389a5f7f6 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sat, 19 Aug 2023 21:34:13 +0200 Subject: [PATCH 2/2] changelog --- CHANGELOG.md | 1 + analysis/src/CompletionBackEnd.ml | 7 +------ analysis/src/SharedTypes.ml | 2 +- analysis/src/TypeUtils.ml | 7 ++----- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93c9d8ba1..7db9c4332 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ #### :nail_care: Polish - Revamp "Insert missing cases" code action to make it apply in more cases and be much more robust. https://github.com/rescript-lang/rescript-vscode/pull/804 +- Make the completion engine understand async/await. https://github.com/rescript-lang/rescript-vscode/pull/813 #### :bug: Bug Fix diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml index 08a9eabe8..15db181c1 100644 --- a/analysis/src/CompletionBackEnd.ml +++ b/analysis/src/CompletionBackEnd.ml @@ -742,13 +742,8 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact ~exact:true ~scope |> completionsGetCompletionType ~full with - | Some (Tpromise (env, TypeExpr typ), _env) -> + | Some (Tpromise (env, typ), _env) -> [Completion.create "dummy" ~env ~kind:(Completion.Value typ)] - | Some (Tpromise (env, ExtractedType typ), _env) -> - [ - Completion.create "dummy" ~env - ~kind:(Completion.ExtractedType (typ, `Type)); - ] | _ -> []) | CPId (path, completionContext) -> path diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml index 54105c4bb..8e60f1cf4 100644 --- a/analysis/src/SharedTypes.ml +++ b/analysis/src/SharedTypes.ml @@ -310,7 +310,7 @@ type innerType = TypeExpr of Types.type_expr | ExtractedType of completionType and completionType = | Tuple of QueryEnv.t * Types.type_expr list * Types.type_expr | Texn of QueryEnv.t - | Tpromise of QueryEnv.t * innerType + | Tpromise of QueryEnv.t * Types.type_expr | Toption of QueryEnv.t * innerType | Tbool of QueryEnv.t | Tarray of QueryEnv.t * innerType diff --git a/analysis/src/TypeUtils.ml b/analysis/src/TypeUtils.ml index 0cb30c21f..0afeb2490 100644 --- a/analysis/src/TypeUtils.ml +++ b/analysis/src/TypeUtils.ml @@ -116,7 +116,7 @@ let rec extractType ~env ~package (t : Types.type_expr) = | Tconstr (Path.Pident {name = "option"}, [payloadTypeExpr], _) -> Some (Toption (env, TypeExpr payloadTypeExpr)) | Tconstr (Path.Pident {name = "promise"}, [payloadTypeExpr], _) -> - Some (Tpromise (env, TypeExpr payloadTypeExpr)) + Some (Tpromise (env, payloadTypeExpr)) | Tconstr (Path.Pident {name = "array"}, [payloadTypeExpr], _) -> Some (Tarray (env, TypeExpr payloadTypeExpr)) | Tconstr (Path.Pident {name = "bool"}, [], _) -> Some (Tbool env) @@ -597,10 +597,7 @@ let rec extractedTypeToString ?(inner = false) = function "option<" ^ Shared.typeToString innerTyp ^ ">" | Toption (_, ExtractedType innerTyp) -> "option<" ^ extractedTypeToString ~inner:true innerTyp ^ ">" - | Tpromise (_, TypeExpr innerTyp) -> - "promise<" ^ Shared.typeToString innerTyp ^ ">" - | Tpromise (_, ExtractedType innerTyp) -> - "promise<" ^ extractedTypeToString ~inner:true innerTyp ^ ">" + | Tpromise (_, innerTyp) -> "promise<" ^ Shared.typeToString innerTyp ^ ">" | Tvariant {variantDecl; variantName} -> if inner then variantName else Shared.declToString variantName variantDecl | Trecord {definition = `NameOnly name; fields} ->