diff --git a/analysis/bin/main.ml b/analysis/bin/main.ml index 259b1a3004..e81b62b0df 100644 --- a/analysis/bin/main.ml +++ b/analysis/bin/main.ml @@ -143,10 +143,10 @@ let main () = ~pos:(int_of_string line, int_of_string col) ~debug | [_; "documentSymbol"; path] -> DocumentSymbol.command ~path - | [_; "hover"; path; line; col; currentFile; supportsMarkdownLinks] -> + | [_; "hover"; path; line; col; _currentFile; supportsMarkdownLinks] -> Commands.hover ~path ~pos:(int_of_string line, int_of_string col) - ~currentFile ~debug + ~debug ~supportsMarkdownLinks: (match supportsMarkdownLinks with | "true" -> true diff --git a/analysis/reanalyze/src/Arnold.ml b/analysis/reanalyze/src/Arnold.ml index 9b31743603..e806bc59bb 100644 --- a/analysis/reanalyze/src/Arnold.ml +++ b/analysis/reanalyze/src/Arnold.ml @@ -582,9 +582,9 @@ module ExtendFunctionTable = struct Texp_apply {funct = {exp_desc = Texp_ident (path, {loc}, _)}; args}; } when kindOpt <> None -> - let checkArg ((argLabel : Asttypes.Noloc.arg_label), _argOpt) = + let checkArg ((argLabel : Asttypes.arg_label), _argOpt) = match (argLabel, kindOpt) with - | (Labelled l | Optional l), Some kind -> + | (Labelled {txt = l} | Optional {txt = l}), Some kind -> kind |> List.for_all (fun {Kind.label} -> label <> l) | _ -> true in @@ -624,9 +624,9 @@ module ExtendFunctionTable = struct when callee |> FunctionTable.isInFunctionInTable ~functionTable -> let functionName = Path.name callee in args - |> List.iter (fun ((argLabel : Asttypes.Noloc.arg_label), argOpt) -> + |> List.iter (fun ((argLabel : Asttypes.arg_label), argOpt) -> match (argLabel, argOpt |> extractLabelledArgument) with - | Labelled label, Some (path, loc) + | Labelled {txt = label}, Some (path, loc) when path |> FunctionTable.isInFunctionInTable ~functionTable -> functionTable @@ -672,11 +672,11 @@ module CheckExpressionWellFormed = struct -> let functionName = Path.name functionPath in args - |> List.iter (fun ((argLabel : Asttypes.Noloc.arg_label), argOpt) -> + |> List.iter (fun ((argLabel : Asttypes.arg_label), argOpt) -> match argOpt |> ExtendFunctionTable.extractLabelledArgument with | Some (path, loc) -> ( match argLabel with - | Labelled label -> ( + | Labelled {txt = label} -> ( if functionTable |> FunctionTable.functionGetKindOfLabel ~functionName @@ -761,7 +761,7 @@ module Compile = struct let argsFromKind = innerFunctionDefinition.kind |> List.map (fun (entry : Kind.entry) -> - ( Asttypes.Noloc.Labelled entry.label, + ( Asttypes.Labelled (Location.mknoloc entry.label), Some { expr with @@ -785,7 +785,7 @@ module Compile = struct args |> List.find_opt (fun arg -> match arg with - | Asttypes.Noloc.Labelled s, Some _ -> s = label + | Asttypes.Labelled {txt = s}, Some _ -> s = label | _ -> false) in let argOpt = diff --git a/analysis/reanalyze/src/DeadValue.ml b/analysis/reanalyze/src/DeadValue.ml index 57ddeccd26..df8b6aa0e2 100644 --- a/analysis/reanalyze/src/DeadValue.ml +++ b/analysis/reanalyze/src/DeadValue.ml @@ -104,7 +104,7 @@ let processOptionalArgs ~expType ~(locFrom : Location.t) ~locTo ~path args = | None -> Some false in match lbl with - | Asttypes.Noloc.Optional s when not locFrom.loc_ghost -> + | Asttypes.Optional {txt = s} when not locFrom.loc_ghost -> if argIsSupplied <> Some false then supplied := s :: !supplied; if argIsSupplied = None then suppliedMaybe := s :: !suppliedMaybe | _ -> ()); diff --git a/analysis/src/Commands.ml b/analysis/src/Commands.ml index 464b3fa53d..e13ccacfdc 100644 --- a/analysis/src/Commands.ml +++ b/analysis/src/Commands.ml @@ -57,27 +57,20 @@ let codeLens ~path ~debug = in print_endline result -let hover ~path ~pos ~currentFile ~debug ~supportsMarkdownLinks = +let hover ~path ~pos ~debug ~supportsMarkdownLinks = let result = match Cmt.loadFullCmtFromPath ~path with | None -> Protocol.null | Some full -> ( match References.getLocItem ~full ~pos ~debug with - | None -> ( - if debug then - Printf.printf - "Nothing at that position. Now trying to use completion.\n"; - match - Hover.getHoverViaCompletions ~debug ~path ~pos ~currentFile - ~forHover:true ~supportsMarkdownLinks - with - | None -> Protocol.null - | Some hover -> hover) + | None -> Protocol.null | Some locItem -> ( let isModule = match locItem.locType with | LModule _ | TopLevelModule _ -> true - | TypeDefinition _ | Typed _ | Constant _ -> false + | TypeDefinition _ | Typed _ | Constant _ | OtherExpression _ + | OtherPattern _ -> + false in let uriLocOpt = References.definitionForLocItem ~full locItem in let skipZero = @@ -135,7 +128,9 @@ let definition ~path ~pos ~debug = let isModule = match locItem.locType with | LModule _ | TopLevelModule _ -> true - | TypeDefinition _ | Typed _ | Constant _ -> false + | TypeDefinition _ | Typed _ | Constant _ | OtherExpression _ + | OtherPattern _ -> + false in let skipLoc = (not isModule) && (not isInterface) && posIsZero loc.loc_start @@ -393,8 +388,7 @@ let test ~path = ("Hover " ^ path ^ " " ^ string_of_int line ^ ":" ^ string_of_int col); let currentFile = createCurrentFile () in - hover ~supportsMarkdownLinks:true ~path ~pos:(line, col) - ~currentFile ~debug:true; + hover ~supportsMarkdownLinks:true ~path ~pos:(line, col) ~debug:true; Sys.remove currentFile | "she" -> print_endline diff --git a/analysis/src/CompletionBackEndRevamped.ml b/analysis/src/CompletionBackEndRevamped.ml new file mode 100644 index 0000000000..b0d2b028ce --- /dev/null +++ b/analysis/src/CompletionBackEndRevamped.ml @@ -0,0 +1,64 @@ +open SharedTypes + +let resolveOpens = CompletionBackEnd.resolveOpens +let getOpens = CompletionBackEnd.getOpens + +let findFields ~env ~package ~hint typ = + match TypeUtils.extractRecordType ~env ~package typ with + | None -> [] + | Some (_recordEnv, fields, decl) -> + fields + |> DotCompletionUtils.filterRecordFields ~env ~prefix:hint ~exact:false + ~recordAsString:(decl.item.decl |> Shared.declToString decl.name.txt) + +let processCompletable ~debug ~full ~scope ~env ~pos + (completable : CompletableRevamped.t) = + let package = full.package in + let rawOpens = Scope.getRawOpens scope in + let opens = getOpens ~debug ~rawOpens ~package ~env in + let allFiles = allFilesInPackage package in + + ignore pos; + ignore opens; + ignore allFiles; + + match completable with + | Cexpression {kind; typeLoc} -> ( + match TypeUtils.findTypeViaLoc typeLoc ~full ~debug with + | None -> [] + | Some typ -> ( + match kind with + | Field {hint} -> findFields ~env ~package ~hint typ)) + | Cnone -> [] + | CextensionNode _ -> [] + | Cdecorator prefix -> + let mkDecorator (name, docstring, maybeInsertText) = + { + (Completion.create name ~synthetic:true ~includesSnippets:true + ~kind:(Label "") ~env ?insertText:maybeInsertText) + with + docstring; + } + in + let isTopLevel = String.starts_with ~prefix:"@" prefix in + let prefix = + if isTopLevel then String.sub prefix 1 (String.length prefix - 1) + else prefix + in + let decorators = + if isTopLevel then CompletionDecorators.toplevel + else CompletionDecorators.local + in + decorators + |> List.filter (fun (decorator, _, _) -> Utils.startsWith decorator prefix) + |> List.map (fun (decorator, maybeInsertText, doc) -> + let parts = String.split_on_char '.' prefix in + let len = String.length prefix in + let dec2 = + if List.length parts > 1 then + String.sub decorator len (String.length decorator - len) + else decorator + in + (dec2, doc, maybeInsertText)) + |> List.map mkDecorator + | CdecoratorPayload _ -> [] diff --git a/analysis/src/CompletionFrontEndRevamped.ml b/analysis/src/CompletionFrontEndRevamped.ml new file mode 100644 index 0000000000..6b89bdae19 --- /dev/null +++ b/analysis/src/CompletionFrontEndRevamped.ml @@ -0,0 +1,750 @@ +open SharedTypes + +let completionWithParser ~currentFile ~debug ~offset ~path ~posCursor text = + let offsetNoWhite = Utils.skipWhite text (offset - 1) in + let posNoWhite = + let line, col = posCursor in + (line, max 0 col - offset + offsetNoWhite) + in + (* Identifies the first character before the cursor that's not white space. + Should be used very sparingly, but can be used to drive completion triggering + in scenarios where the parser eats things we'd need to complete. + Example: let {whatever, }, char is ','. *) + let firstCharBeforeCursorNoWhite = + if offsetNoWhite < String.length text && offsetNoWhite >= 0 then + Some text.[offsetNoWhite] + else None + in + let posOfDot = Pos.posOfDot text ~pos:posCursor ~offset in + let charAtCursor = + if offset < String.length text then text.[offset] else '\n' + in + let posBeforeCursor = Pos.posBeforeCursor posCursor in + let _charBeforeCursor, blankAfterCursor = + match Pos.positionToOffset text posCursor with + | Some offset when offset > 0 -> ( + let charBeforeCursor = text.[offset - 1] in + match charAtCursor with + | ' ' | '\t' | '\r' | '\n' -> + (Some charBeforeCursor, Some charBeforeCursor) + | _ -> (Some charBeforeCursor, None)) + | _ -> (None, None) + in + let flattenLidCheckDot ?(jsx = true) (lid : Longident.t Location.loc) = + (* Flatten an identifier keeping track of whether the current cursor + is after a "." in the id followed by a blank character. + In that case, cut the path after ".". *) + let cutAtOffset = + let idStart = Loc.start lid.loc in + match blankAfterCursor with + | Some '.' -> + if fst posBeforeCursor = fst idStart then + Some (snd posBeforeCursor - snd idStart) + else None + | _ -> None + in + Utils.flattenLongIdent ~cutAtOffset ~jsx lid.txt + in + + let found = ref false in + let result = ref None in + let scope = ref (Scope.create ()) in + let setResultOpt x = + if !result = None then + match x with + | None -> + if Debug.verbose () then + print_endline + "[set_result] did not set new result because result already was set"; + () + | Some x -> result := Some (x, !scope) + in + + let setResult (x : CompletableRevamped.t) = setResultOpt (Some x) in + let scopeValueDescription (vd : Parsetree.value_description) = + scope := + !scope |> Scope.addValue ~name:vd.pval_name.txt ~loc:vd.pval_name.loc + in + let rec scopePattern (pat : Parsetree.pattern) = + match pat.ppat_desc with + | Ppat_any -> () + | Ppat_var {txt; loc} -> scope := !scope |> Scope.addValue ~name:txt ~loc + | Ppat_alias (p, asA) -> + scopePattern p; + scope := !scope |> Scope.addValue ~name:asA.txt ~loc:asA.loc + | Ppat_constant _ | Ppat_interval _ -> () + | Ppat_tuple pl -> pl |> List.iter (fun p -> scopePattern p) + | Ppat_construct (_, None) -> () + | Ppat_construct (_, Some {ppat_desc = Ppat_tuple pl}) -> + pl |> List.iter (fun p -> scopePattern p) + | Ppat_construct (_, Some p) -> scopePattern p + | Ppat_variant (_, None) -> () + | Ppat_variant (_, Some {ppat_desc = Ppat_tuple pl}) -> + pl |> List.iter (fun p -> scopePattern p) + | Ppat_variant (_, Some p) -> scopePattern p + | Ppat_record (fields, _) -> + fields |> List.iter (fun (_fname, p, _) -> scopePattern p) + | Ppat_array pl -> pl |> List.iter scopePattern + | Ppat_or (p1, _) -> scopePattern p1 + | Ppat_constraint (p, _coreType) -> scopePattern p + | Ppat_type _ -> () + | Ppat_lazy p -> scopePattern p + | Ppat_unpack {txt; loc} -> scope := !scope |> Scope.addValue ~name:txt ~loc + | Ppat_exception p -> scopePattern p + | Ppat_extension _ -> () + | Ppat_open (_, p) -> scopePattern p + in + let locHasCursor = CursorPosition.locHasCursor ~pos:posBeforeCursor in + let locIsEmpty = CursorPosition.locIsEmpty ~pos:posBeforeCursor in + let scopeValueBinding (vb : Parsetree.value_binding) = + scopePattern vb.pvb_pat + in + let scopeTypeKind (tk : Parsetree.type_kind) = + match tk with + | Ptype_variant constrDecls -> + constrDecls + |> List.iter (fun (cd : Parsetree.constructor_declaration) -> + scope := + !scope + |> Scope.addConstructor ~name:cd.pcd_name.txt ~loc:cd.pcd_loc) + | Ptype_record labelDecls -> + labelDecls + |> List.iter (fun (ld : Parsetree.label_declaration) -> + scope := + !scope |> Scope.addField ~name:ld.pld_name.txt ~loc:ld.pld_loc) + | _ -> () + in + let scopeTypeDeclaration (td : Parsetree.type_declaration) = + scope := + !scope |> Scope.addType ~name:td.ptype_name.txt ~loc:td.ptype_name.loc; + scopeTypeKind td.ptype_kind + in + let scopeModuleBinding (mb : Parsetree.module_binding) = + scope := + !scope |> Scope.addModule ~name:mb.pmb_name.txt ~loc:mb.pmb_name.loc + in + let scopeModuleDeclaration (md : Parsetree.module_declaration) = + scope := + !scope |> Scope.addModule ~name:md.pmd_name.txt ~loc:md.pmd_name.loc + in + let structure (iterator : Ast_iterator.iterator) + (structure : Parsetree.structure) = + let oldScope = !scope in + Ast_iterator.default_iterator.structure iterator structure; + scope := oldScope + in + let structure_item (iterator : Ast_iterator.iterator) + (item : Parsetree.structure_item) = + let processed = ref false in + (match item.pstr_desc with + | Pstr_open {popen_lid} -> + scope := !scope |> Scope.addOpen ~lid:popen_lid.txt + | Pstr_primitive vd -> scopeValueDescription vd + | Pstr_value (recFlag, bindings) -> + if recFlag = Recursive then bindings |> List.iter scopeValueBinding; + bindings |> List.iter (fun vb -> iterator.value_binding iterator vb); + if recFlag = Nonrecursive then bindings |> List.iter scopeValueBinding; + processed := true + | Pstr_type (recFlag, decls) -> + if recFlag = Recursive then decls |> List.iter scopeTypeDeclaration; + decls |> List.iter (fun td -> iterator.type_declaration iterator td); + if recFlag = Nonrecursive then decls |> List.iter scopeTypeDeclaration; + processed := true + | Pstr_module mb -> + iterator.module_binding iterator mb; + scopeModuleBinding mb; + processed := true + | Pstr_recmodule mbs -> + mbs |> List.iter scopeModuleBinding; + mbs |> List.iter (fun b -> iterator.module_binding iterator b); + processed := true + | _ -> ()); + if not !processed then + Ast_iterator.default_iterator.structure_item iterator item + in + let value_binding (iterator : Ast_iterator.iterator) + (value_binding : Parsetree.value_binding) = + Ast_iterator.default_iterator.value_binding iterator value_binding + in + let signature (iterator : Ast_iterator.iterator) + (signature : Parsetree.signature) = + let oldScope = !scope in + Ast_iterator.default_iterator.signature iterator signature; + scope := oldScope + in + let signature_item (iterator : Ast_iterator.iterator) + (item : Parsetree.signature_item) = + let processed = ref false in + (match item.psig_desc with + | Psig_open {popen_lid} -> + scope := !scope |> Scope.addOpen ~lid:popen_lid.txt + | Psig_value vd -> scopeValueDescription vd + | Psig_type (recFlag, decls) -> + if recFlag = Recursive then decls |> List.iter scopeTypeDeclaration; + decls |> List.iter (fun td -> iterator.type_declaration iterator td); + if recFlag = Nonrecursive then decls |> List.iter scopeTypeDeclaration; + processed := true + | Psig_module md -> + iterator.module_declaration iterator md; + scopeModuleDeclaration md; + processed := true + | Psig_recmodule mds -> + mds |> List.iter scopeModuleDeclaration; + mds |> List.iter (fun d -> iterator.module_declaration iterator d); + processed := true + | _ -> ()); + if not !processed then + Ast_iterator.default_iterator.signature_item iterator item + in + let attribute (iterator : Ast_iterator.iterator) + ((id, payload) : Parsetree.attribute) = + (if String.length id.txt >= 4 && String.sub id.txt 0 4 = "res." then + (* skip: internal parser attribute *) () + else if id.loc.loc_ghost then () + else if id.loc |> Loc.hasPos ~pos:posBeforeCursor then + let posStart, posEnd = Loc.range id.loc in + match + (Pos.positionToOffset text posStart, Pos.positionToOffset text posEnd) + with + | Some offsetStart, Some offsetEnd -> + (* Can't trust the parser's location + E.g. @foo. let x... gives as label @foo.let *) + let label = + let rawLabel = + String.sub text offsetStart (offsetEnd - offsetStart) + in + let ( ++ ) x y = + match (x, y) with + | Some i1, Some i2 -> Some (min i1 i2) + | Some _, None -> x + | None, _ -> y + in + let label = + match + String.index_opt rawLabel ' ' + ++ String.index_opt rawLabel '\t' + ++ String.index_opt rawLabel '\r' + ++ String.index_opt rawLabel '\n' + with + | None -> rawLabel + | Some i -> String.sub rawLabel 0 i + in + if label <> "" && label.[0] = '@' then + String.sub label 1 (String.length label - 1) + else label + in + found := true; + if debug then + Printf.printf "Attribute id:%s:%s label:%s\n" id.txt + (Loc.toString id.loc) label; + setResult (Cdecorator label) + | _ -> () + else if id.txt = "module" then + match payload with + | PStr + [ + { + pstr_desc = + Pstr_eval + ( {pexp_loc; pexp_desc = Pexp_constant (Pconst_string (s, _))}, + _ ); + }; + ] + when locHasCursor pexp_loc -> + if Debug.verbose () then + print_endline "[decoratorCompletion] Found @module"; + setResult (CdecoratorPayload (Module s)) + | PStr + [ + { + pstr_desc = + Pstr_eval + ( { + pexp_desc = + Pexp_record + (({txt = Lident "from"}, fromExpr, _) :: _, _); + }, + _ ); + }; + ] + when locHasCursor fromExpr.pexp_loc + || locIsEmpty fromExpr.pexp_loc + && CompletionExpressions.isExprHole fromExpr -> ( + if Debug.verbose () then + print_endline + "[decoratorCompletion] Found @module with import attributes and \ + cursor on \"from\""; + match + ( locHasCursor fromExpr.pexp_loc, + locIsEmpty fromExpr.pexp_loc, + CompletionExpressions.isExprHole fromExpr, + fromExpr ) + with + | true, _, _, {pexp_desc = Pexp_constant (Pconst_string (s, _))} -> + if Debug.verbose () then + print_endline + "[decoratorCompletion] @module `from` payload was string"; + setResult (CdecoratorPayload (Module s)) + | false, true, true, _ -> + if Debug.verbose () then + print_endline + "[decoratorCompletion] @module `from` payload was expr hole"; + setResult (CdecoratorPayload (Module "")) + | _ -> ()) + | PStr [{pstr_desc = Pstr_eval (_expr, _)}] -> + if Debug.verbose () then + print_endline + "[decoratorCompletion] Found @module with non-string payload"; + (* TODO(revamp) Complete *) + () + | _ -> () + else if id.txt = "jsxConfig" then + match payload with + | PStr [{pstr_desc = Pstr_eval (_expr, _)}] -> + if Debug.verbose () then + print_endline "[decoratorCompletion] Found @jsxConfig"; + (* TODO(revamp) Complete *) + () + | _ -> () + else if id.txt = "editor.completeFrom" then + match payload with + | PStr + [ + { + pstr_desc = + Pstr_eval + ( { + pexp_loc; + pexp_desc = Pexp_construct ({txt = _path; loc = _}, None); + }, + _ ); + }; + ] + when locHasCursor pexp_loc -> + if Debug.verbose () then + print_endline "[decoratorCompletion] Found @editor.completeFrom"; + (* TODO(revamp) Complete for module identifier *) + (*setResult + (Completable.Cpath + (CPId + { + path = Utils.flattenLongIdent path; + completionContext = Module; + loc; + }))*) + () + | _ -> ()); + Ast_iterator.default_iterator.attribute iterator (id, payload) + in + let expr (iterator : Ast_iterator.iterator) (expr : Parsetree.expression) = + let processed = ref false in + let setFound () = + found := true; + if debug then + Printf.printf "posCursor:[%s] posNoWhite:[%s] Found expr:%s\n" + (Pos.toString posCursor) (Pos.toString posNoWhite) + (Loc.toString expr.pexp_loc) + in + match expr.pexp_desc with + | Pexp_apply + { + funct = {pexp_desc = Pexp_ident {txt = Lident "->"; loc = opLoc}}; + args = + [ + (_, _lhs); + (_, {pexp_desc = Pexp_extension _; pexp_loc = {loc_ghost = true}}); + ]; + } + when opLoc |> Loc.hasPos ~pos:posBeforeCursor -> + (* Case foo-> when the parser adds a ghost expression to the rhs + so the apply expression does not include the cursor *) + (* TODO(revamp) Complete pipe *) + () + (* + A dot completion for a tagged templated application with an expr hole. + Example: + sh`echo "meh"`. + *) + | Pexp_apply + { + funct = {pexp_desc = Pexp_ident {txt = Lident "."; loc = _}}; + args = + [ + (* sh`echo "meh"` *) + (_, ({pexp_desc = Pexp_apply _} as innerExpr)); + (* recovery inserted node *) + (_, {pexp_desc = Pexp_extension ({txt = "rescript.exprhole"}, _)}); + ]; + } + when Res_parsetree_viewer.is_tagged_template_literal innerExpr -> + (* TODO(revamp) Complete *) + () + (* + A dot completion for a tagged templated application with an ident. + Example: + sh`echo "meh"`.foo + *) + | Pexp_apply + { + funct = {pexp_desc = Pexp_ident {txt = Lident "."; loc = _}}; + args = + [ + (* sh`echo "meh"` *) + (_, ({pexp_desc = Pexp_apply _} as innerExpr)); + (* foo *) + (_, {pexp_desc = Pexp_ident {txt = Lident _fieldName}}); + ]; + } + when Res_parsetree_viewer.is_tagged_template_literal innerExpr + && expr.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor -> + (* TODO(revamp) Complete *) + () + | _ -> + if expr.pexp_loc |> Loc.hasPos ~pos:posNoWhite && !result = None then ( + setFound (); + match expr.pexp_desc with + | Pexp_extension ({txt = "obj"}, PStr [str_item]) -> + Ast_iterator.default_iterator.structure_item iterator str_item + | Pexp_extension ({txt}, _) -> setResult (CextensionNode txt) + | Pexp_constant _ -> setResult Cnone + | Pexp_ident lid -> + let lidPath = flattenLidCheckDot lid in + if lid.loc |> Loc.hasPos ~pos:posBeforeCursor then + let _isLikelyModulePath = + match lidPath with + | head :: _ + when String.length head > 0 + && head.[0] == Char.uppercase_ascii head.[0] -> + true + | _ -> false + in + () + (* TODO(revamp) Complete for module identifier *) + (*setResult + (Cpath + (CPId + { + loc = lid.loc; + path = lidPath; + completionContext = + (if + isLikelyModulePath + && expr |> Res_parsetree_viewer.is_braced_expr + then ValueOrField + else Value); + }))*) + | Pexp_construct ({txt = Lident ("::" | "()")}, _) -> + (* Ignore list expressions, used in JSX, unit, and more *) () + | Pexp_construct (lid, eOpt) -> ( + let lidPath = flattenLidCheckDot lid in + if debug then + Printf.printf "Pexp_construct %s:%s %s\n" + (lidPath |> String.concat "\n") + (Loc.toString lid.loc) + (match eOpt with + | None -> "None" + | Some e -> Loc.toString e.pexp_loc); + if + eOpt = None && (not lid.loc.loc_ghost) + && lid.loc |> Loc.hasPos ~pos:posBeforeCursor + then () + (* TODO(revamp) Complete *) + (* + setResult + (Cpath + (CPId + {loc = lid.loc; path = lidPath; completionContext = Value}))*) + else + match eOpt with + | Some e when locHasCursor e.pexp_loc -> ( + match + CompletionExpressions.completeConstructorPayload + ~posBeforeCursor ~firstCharBeforeCursorNoWhite lid e + with + | Some _result -> + (* Check if anything else more important completes before setting this completion. *) + Ast_iterator.default_iterator.expr iterator e + (* TODO(revamp) Complete *) + (*setResult result*) + | None -> ()) + | _ -> ()) + | Pexp_field (e, fieldName) -> + if locHasCursor fieldName.loc then + match fieldName.txt with + | Lident name -> + setResult + (Cexpression + {kind = Field {hint = name}; typeLoc = e.pexp_loc; posOfDot}) + | Ldot (_id, _name) -> + (* Case x.M.field ignore the x part *) + (*let contextPath = + Completable.CPField + { + contextPath = + CPId + { + loc = fieldName.loc; + path = Utils.flattenLongIdent id; + completionContext = Module; + }; + fieldName = + (if blankAfterCursor = Some '.' then + (* x.M. field ---> M. *) "" + else if name = "_" then "" + else name); + posOfDot; + exprLoc = e.pexp_loc; + inJsx = !inJsxContext; + } + in*) + (* TODO(revamp) Complete ID *) + () + | Lapply _ -> () + else if Loc.end_ e.pexp_loc = posBeforeCursor then + setResult + (Cexpression + {kind = Field {hint = ""}; typeLoc = e.pexp_loc; posOfDot}) + (* TODO(revamp) Insert back JSX stuff *) + | Pexp_apply + { + funct = {pexp_desc = Pexp_ident {txt = Lident "->"}}; + args = + [ + (_, _lhs); + (_, {pexp_desc = Pexp_ident {txt = Longident.Lident _id; loc}}); + ]; + } + when loc |> Loc.hasPos ~pos:posBeforeCursor -> + if Debug.verbose () then print_endline "[expr_iter] Case foo->id"; + (* TODO(revamp) Complete pipe (id) *) + () + | Pexp_apply + { + funct = {pexp_desc = Pexp_ident {txt = Lident "->"; loc = opLoc}}; + args = [(_, _lhs); _]; + } + when Loc.end_ opLoc = posCursor -> + if Debug.verbose () then print_endline "[expr_iter] Case foo->"; + (* TODO(revamp) Complete pipe (empty) *) + () + | Pexp_send (lhs, {txt; loc}) -> + (* e["txt"] + If the string for txt is not closed, it could go over several lines. + Only take the first like to represent the label *) + let txtLines = txt |> String.split_on_char '\n' in + let label = List.hd txtLines in + let label = + if label <> "" && label.[String.length label - 1] = '\r' then + String.sub label 0 (String.length label - 1) + else label + in + let labelRange = + let l, c = Loc.start loc in + ((l, c + 1), (l, c + 1 + String.length label)) + in + if debug then + Printf.printf "Pexp_send %s%s e:%s\n" label + (Range.toString labelRange) + (Loc.toString lhs.pexp_loc); + if + labelRange |> Range.hasPos ~pos:posBeforeCursor + || (label = "" && posCursor = fst labelRange) + then + (* TODO(revamp) Complete obj *) + () + | Pexp_fun + {arg_label = _lbl; default = _defaultExpOpt; lhs = pat; rhs = e} -> + let oldScope = !scope in + scopePattern pat; + iterator.pat iterator pat; + iterator.expr iterator e; + scope := oldScope; + processed := true + | Pexp_let (recFlag, bindings, e) -> + let oldScope = !scope in + if recFlag = Recursive then bindings |> List.iter scopeValueBinding; + bindings |> List.iter (fun vb -> iterator.value_binding iterator vb); + if recFlag = Nonrecursive then bindings |> List.iter scopeValueBinding; + iterator.expr iterator e; + scope := oldScope; + processed := true + | Pexp_letmodule (name, modExpr, modBody) -> + let oldScope = !scope in + iterator.location iterator name.loc; + iterator.module_expr iterator modExpr; + scope := !scope |> Scope.addModule ~name:name.txt ~loc:name.loc; + iterator.expr iterator modBody; + scope := oldScope; + processed := true + | Pexp_open (_, lid, e) -> + let oldScope = !scope in + iterator.location iterator lid.loc; + scope := !scope |> Scope.addOpen ~lid:lid.txt; + iterator.expr iterator e; + scope := oldScope; + processed := true + | _ -> ()); + if not !processed then Ast_iterator.default_iterator.expr iterator expr + in + let typ (iterator : Ast_iterator.iterator) (core_type : Parsetree.core_type) = + if core_type.ptyp_loc |> Loc.hasPos ~pos:posNoWhite then ( + found := true; + if debug then + Printf.printf "posCursor:[%s] posNoWhite:[%s] Found type:%s\n" + (Pos.toString posCursor) (Pos.toString posNoWhite) + (Loc.toString core_type.ptyp_loc); + match core_type.ptyp_desc with + | Ptyp_constr (lid, _args) -> + let lidPath = flattenLidCheckDot lid in + if debug then + Printf.printf "Ptyp_constr %s:%s\n" + (lidPath |> String.concat ".") + (Loc.toString lid.loc); + if lid.loc |> Loc.hasPos ~pos:posBeforeCursor then + (* TODO(revamp) Complete type *) + () + | _ -> ()); + Ast_iterator.default_iterator.typ iterator core_type + in + let pat (iterator : Ast_iterator.iterator) (pat : Parsetree.pattern) = + if pat.ppat_loc |> Loc.hasPos ~pos:posNoWhite then ( + found := true; + if debug then + Printf.printf "posCursor:[%s] posNoWhite:[%s] Found pattern:%s\n" + (Pos.toString posCursor) (Pos.toString posNoWhite) + (Loc.toString pat.ppat_loc); + (match pat.ppat_desc with + | Ppat_construct (lid, _) -> + let lidPath = flattenLidCheckDot lid in + if debug then + Printf.printf "Ppat_construct %s:%s\n" + (lidPath |> String.concat ".") + (Loc.toString lid.loc); + let _completion = + Completable.Cpath + (CPId {loc = lid.loc; path = lidPath; completionContext = Value}) + in + (* TODO(revamp) Complete *) + () + | _ -> ()); + Ast_iterator.default_iterator.pat iterator pat) + in + let module_expr (iterator : Ast_iterator.iterator) + (me : Parsetree.module_expr) = + (match me.pmod_desc with + | Pmod_ident lid when lid.loc |> Loc.hasPos ~pos:posBeforeCursor -> + let lidPath = flattenLidCheckDot lid in + if debug then + Printf.printf "Pmod_ident %s:%s\n" + (lidPath |> String.concat ".") + (Loc.toString lid.loc); + found := true + (* TODO(revamp) Complete module ID *) + (* + setResult + (Cpath + (CPId {loc = lid.loc; path = lidPath; completionContext = Module}))*) + | _ -> ()); + Ast_iterator.default_iterator.module_expr iterator me + in + let module_type (iterator : Ast_iterator.iterator) + (mt : Parsetree.module_type) = + (match mt.pmty_desc with + | Pmty_ident lid when lid.loc |> Loc.hasPos ~pos:posBeforeCursor -> + let lidPath = flattenLidCheckDot lid in + if debug then + Printf.printf "Pmty_ident %s:%s\n" + (lidPath |> String.concat ".") + (Loc.toString lid.loc); + found := true + (* TODO(revamp) Complete module ID *) + (* + setResult + (Cpath + (CPId {loc = lid.loc; path = lidPath; completionContext = Module}))*) + | _ -> ()); + Ast_iterator.default_iterator.module_type iterator mt + in + let type_kind (iterator : Ast_iterator.iterator) + (type_kind : Parsetree.type_kind) = + (match type_kind with + | Ptype_variant [decl] + when decl.pcd_name.loc |> Loc.hasPos ~pos:posNoWhite + && decl.pcd_args = Pcstr_tuple [] -> + (* "type t = Pre" could signal the intent to complete variant "Prelude", + or the beginning of "Prefix.t" *) + if debug then + Printf.printf "Ptype_variant unary %s:%s\n" decl.pcd_name.txt + (Loc.toString decl.pcd_name.loc); + found := true + (* TODO(revamp) Complete *) + (*setResult + (Cpath + (CPId + { + loc = decl.pcd_name.loc; + path = [decl.pcd_name.txt]; + completionContext = Value; + }))*) + | _ -> ()); + Ast_iterator.default_iterator.type_kind iterator type_kind + in + + let lastScopeBeforeCursor = ref (Scope.create ()) in + let location (_iterator : Ast_iterator.iterator) (loc : Location.t) = + if Loc.end_ loc <= posCursor then lastScopeBeforeCursor := !scope + in + + let iterator = + { + Ast_iterator.default_iterator with + attribute; + expr; + location; + module_expr; + module_type; + pat; + signature; + signature_item; + structure; + structure_item; + typ; + type_kind; + value_binding; + } + in + + if Filename.check_suffix path ".res" then ( + let parser = + Res_driver.parsing_engine.parse_implementation ~for_printer:false + in + let {Res_driver.parsetree = str} = parser ~filename:currentFile in + iterator.structure iterator str |> ignore; + if blankAfterCursor = Some ' ' || blankAfterCursor = Some '\n' then + scope := !lastScopeBeforeCursor + (* TODO(revamp) Complete any value *) + (*setResult + (Cpath + (CPId {loc = Location.none; path = [""]; completionContext = Value}))*); + if !found = false then if debug then Printf.printf "XXX Not found!\n"; + !result) + else if Filename.check_suffix path ".resi" then ( + let parser = Res_driver.parsing_engine.parse_interface ~for_printer:false in + let {Res_driver.parsetree = signature} = parser ~filename:currentFile in + iterator.signature iterator signature |> ignore; + if blankAfterCursor = Some ' ' || blankAfterCursor = Some '\n' then + scope := !lastScopeBeforeCursor + (* TODO(revamp) Complete any type *) + (*setResult + setResult + (Cpath + (CPId {loc = Location.none; path = [""]; completionContext = Type}))*); + if !found = false then if debug then Printf.printf "XXX Not found!\n"; + !result) + else None + +let completionWithParser ~debug ~path ~posCursor ~currentFile ~text = + match Pos.positionToOffset text posCursor with + | Some offset -> + completionWithParser ~currentFile ~debug ~offset ~path ~posCursor text + | None -> None diff --git a/analysis/src/Completions.ml b/analysis/src/Completions.ml index 42176bb3b0..969705f7d0 100644 --- a/analysis/src/Completions.ml +++ b/analysis/src/Completions.ml @@ -1,11 +1,12 @@ let getCompletions ~debug ~path ~pos ~currentFile ~forHover = + ignore forHover; let textOpt = Files.readFile currentFile in match textOpt with | None | Some "" -> None | Some text -> ( match - CompletionFrontEnd.completionWithParser ~debug ~path ~posCursor:pos - ~currentFile ~text + CompletionFrontEndRevamped.completionWithParser ~debug ~path + ~posCursor:pos ~currentFile ~text with | None -> None | Some (completable, scope) -> ( @@ -16,7 +17,7 @@ let getCompletions ~debug ~path ~pos ~currentFile ~forHover = let env = SharedTypes.QueryEnv.fromFile full.file in let completables = completable - |> CompletionBackEnd.processCompletable ~debug ~full ~pos ~scope ~env - ~forHover + |> CompletionBackEndRevamped.processCompletable ~debug ~full ~pos + ~scope ~env in Some (completables, full, scope))) diff --git a/analysis/src/Hover.ml b/analysis/src/Hover.ml index f0979d695c..f6a4d24fb9 100644 --- a/analysis/src/Hover.ml +++ b/analysis/src/Hover.ml @@ -244,6 +244,8 @@ let newHover ~full:{file; package} ~supportsMarkdownLinks locItem = showModule ~docstring:file.structure.docstring ~name:file.moduleName ~file ~package None) | Typed (_, _, Definition (_, (Field _ | Constructor _))) -> None + | OtherExpression t | OtherPattern t -> + Some (Markdown.codeBlock (Shared.typeToString t)) | Constant t -> Some (Markdown.codeBlock diff --git a/analysis/src/ProcessExtra.ml b/analysis/src/ProcessExtra.ml index 1710d5fd32..70e26adfd1 100644 --- a/analysis/src/ProcessExtra.ml +++ b/analysis/src/ProcessExtra.ml @@ -373,7 +373,8 @@ let pat ~(file : File.t) ~env ~extra (iter : Tast_iterator.iterator) (* Log.log("Entering pattern " ++ Utils.showLocation(pat_loc)); *) (match pattern.pat_desc with | Tpat_record (items, _) -> - addForRecord ~env ~extra ~recordType:pattern.pat_type items + addForRecord ~env ~extra ~recordType:pattern.pat_type items; + addLocItem extra pattern.pat_loc (OtherPattern pattern.pat_type) | Tpat_construct (lident, constructor, _) -> addForConstructor ~env ~extra pattern.pat_type lident constructor | Tpat_alias (_inner, ident, name) -> @@ -383,7 +384,7 @@ let pat ~(file : File.t) ~env ~extra (iter : Tast_iterator.iterator) (* Log.log("Pattern " ++ name.txt); *) let stamp = Ident.binding_time ident in addForPattern stamp name - | _ -> ()); + | _ -> addLocItem extra pattern.pat_loc (OtherPattern pattern.pat_type)); Tast_iterator.default_iterator.pat iter pattern let expr ~env ~(extra : extra) (iter : Tast_iterator.iterator) @@ -397,7 +398,8 @@ let expr ~env ~(extra : extra) (iter : Tast_iterator.iterator) |> Utils.filterMap (fun (desc, item, opt) -> match item with | Typedtree.Overridden (loc, _) -> Some (loc, desc, (), opt) - | _ -> None)) + | _ -> None)); + addLocItem extra expression.exp_loc (OtherExpression expression.exp_type) | Texp_constant constant -> addLocItem extra expression.exp_loc (Constant constant) (* Skip unit and list literals *) @@ -409,7 +411,25 @@ let expr ~env ~(extra : extra) (iter : Tast_iterator.iterator) | Texp_field (inner, lident, _label_description) -> addForField ~env ~extra ~recordType:inner.exp_type ~fieldType:expression.exp_type lident - | _ -> ()); + | Texp_apply {funct; args} -> + args + |> List.iter (fun (label, _) -> + match label with + | Asttypes.Labelled {txt; loc} | Optional {txt; loc} -> ( + let rec findArgType (t : Types.type_expr) = + match t.desc with + | Tarrow ((Labelled lbl | Optional lbl), argType, _, _, _) + when lbl = txt -> + Some argType + | Tarrow (_, _, next, _, _) -> findArgType next + | _ -> None + in + match findArgType funct.exp_type with + | None -> () + | Some argType -> addLocItem extra loc (OtherExpression argType)) + | _ -> ()) + | _ -> + addLocItem extra expression.exp_loc (OtherExpression expression.exp_type)); Tast_iterator.default_iterator.expr iter expression let getExtra ~file ~infos = diff --git a/analysis/src/References.ml b/analysis/src/References.ml index e047a2ba18..086cbd0175 100644 --- a/analysis/src/References.ml +++ b/analysis/src/References.ml @@ -358,7 +358,7 @@ let definitionForLocItem ~full:{file; package} locItem = | Typed (_, _, NotFound) | LModule (NotFound | Definition (_, _)) | TypeDefinition (_, _, _) - | Constant _ -> + | Constant _ | OtherExpression _ | OtherPattern _ -> None | TopLevelModule name -> ( maybeLog ("Toplevel " ^ name); @@ -405,7 +405,9 @@ let digConstructor ~env ~package path = let typeDefinitionForLocItem ~full:{file; package} locItem = match locItem.locType with - | Constant _ | TopLevelModule _ | LModule _ -> None + | Constant _ | TopLevelModule _ | LModule _ | OtherExpression _ + | OtherPattern _ -> + None | TypeDefinition _ -> Some (file.uri, locItem.loc) | Typed (_, typ, _) -> ( let env = QueryEnv.fromFile file in @@ -546,7 +548,10 @@ let allReferencesForLocItem ~full:({file; package} as full) locItem = getSrc paths |> List.map moduleSrcToRef in List.append targetModuleReferences otherModulesReferences - | Typed (_, _, NotFound) | LModule NotFound | Constant _ -> [] + | Typed (_, _, NotFound) + | LModule NotFound + | Constant _ | OtherExpression _ | OtherPattern _ -> + [] | TypeDefinition (_, _, stamp) -> forLocalStamp ~full stamp Type | Typed (_, _, (LocalReference (stamp, tip) | Definition (stamp, tip))) | LModule (LocalReference (stamp, tip) | Definition (stamp, tip)) -> diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml index 17b74e3cf2..63d87356d1 100644 --- a/analysis/src/SharedTypes.ml +++ b/analysis/src/SharedTypes.ml @@ -460,6 +460,9 @@ type locType = | LModule of locKind | TopLevelModule of string | TypeDefinition of string * Types.type_declaration * int + (* For all other expressions and patterns that are not tracked by the above. Needed to produce hovers, completions, and what not. *) + | OtherExpression of Types.type_expr + | OtherPattern of Types.type_expr type locItem = {loc: Location.t; locType: locType} @@ -534,6 +537,8 @@ let locTypeToString = function "Typed " ^ name ^ " " ^ Shared.typeToString e ^ " " ^ locKindToString locKind | Constant _ -> "Constant" + | OtherExpression e -> "OtherExpression " ^ Shared.typeToString e + | OtherPattern e -> "OtherPattern " ^ Shared.typeToString e | LModule locKind -> "LModule " ^ locKindToString locKind | TopLevelModule _ -> "TopLevelModule" | TypeDefinition _ -> "TypeDefinition" @@ -764,6 +769,26 @@ module Completable = struct | ChtmlElement {prefix} -> "ChtmlElement <" ^ prefix end +module CompletableRevamped = struct + type decoratorPayload = + | Module of string + | ModuleWithImportAttributes of {prefix: string} + | JsxConfig of {prefix: string} + + type completionKind = Field of {hint: string} + + type t = + | Cexpression of { + kind: completionKind; + typeLoc: Location.t; + posOfDot: Pos.t option; + } + | Cnone + | CextensionNode of string + | Cdecorator of string + | CdecoratorPayload of decoratorPayload +end + module ScopeTypes = struct type item = | Constructor of string * Location.t diff --git a/analysis/src/TypeUtils.ml b/analysis/src/TypeUtils.ml index c9b1acd011..8340c3df90 100644 --- a/analysis/src/TypeUtils.ml +++ b/analysis/src/TypeUtils.ml @@ -37,7 +37,12 @@ let rec hasTvar (ty : Types.type_expr) : bool = let findTypeViaLoc ~full ~debug (loc : Location.t) = match References.getLocItem ~full ~pos:(Pos.ofLexing loc.loc_end) ~debug with - | Some {locType = Typed (_, typExpr, _)} -> Some typExpr + | Some + { + locType = + Typed (_, typExpr, _) | OtherExpression typExpr | OtherPattern typExpr; + } -> + Some typExpr | _ -> None let pathFromTypeExpr (t : Types.type_expr) = diff --git a/compiler/bsc/rescript_compiler_main.ml b/compiler/bsc/rescript_compiler_main.ml index 358ece0799..e28fd26dea 100644 --- a/compiler/bsc/rescript_compiler_main.ml +++ b/compiler/bsc/rescript_compiler_main.ml @@ -369,6 +369,9 @@ let buckle_script_flags : (string * Bsc_args.spec * string) array = ( "-ignore-parse-errors", set Clflags.ignore_parse_errors, "*internal* continue after parse errors" ); + ( "-editor-mode", + set Clflags.editor_mode, + "*internal* editor mode. Adapts compilation for editors." ); ( "-where", unit_call print_standard_library, "*internal* Print location of standard library and exit" ); @@ -453,6 +456,9 @@ let _ : unit = | Bsc_args.Bad msg -> Format.eprintf "%s@." msg; exit 2 + | Typecore.Errors exns -> + exns |> List.rev |> List.iter (Location.report_exception ppf); + exit 2 | x -> (* Ext_obj.bt (); diff --git a/compiler/core/js_implementation.ml b/compiler/core/js_implementation.ml index 5f4e4e6c76..001a3eb763 100644 --- a/compiler/core/js_implementation.ml +++ b/compiler/core/js_implementation.ml @@ -138,6 +138,7 @@ let after_parsing_impl ppf outputprefix (ast : Parsetree.structure) = ?check_exists:(if !Js_config.force_cmi then None else Some ()) !Location.input_name outputprefix modulename env ast in + if !Clflags.editor_mode then Typecore.raise_delayed_error_if_exists (); let typedtree_coercion = (typedtree, coercion) in print_if ppf Clflags.dump_typedtree Printtyped.implementation_with_coercion typedtree_coercion; diff --git a/compiler/ml/clflags.ml b/compiler/ml/clflags.ml index 2b663ba24e..af9974dc14 100644 --- a/compiler/ml/clflags.ml +++ b/compiler/ml/clflags.ml @@ -42,6 +42,10 @@ and only_parse = ref false (* -only-parse *) and ignore_parse_errors = ref false (* -ignore-parse-errors *) +and editor_mode = ref true +(* -editor-mode *) +(* true for easy testing *) + let dont_write_files = ref false (* set to true under ocamldoc *) let reset_dump_state () = diff --git a/compiler/ml/clflags.mli b/compiler/ml/clflags.mli index c861614928..0cb5f1ea3e 100644 --- a/compiler/ml/clflags.mli +++ b/compiler/ml/clflags.mli @@ -25,6 +25,7 @@ val dont_write_files : bool ref val keep_locs : bool ref val only_parse : bool ref val ignore_parse_errors : bool ref +val editor_mode : bool ref val parse_color_setting : string -> Misc.Color.setting option val color : Misc.Color.setting option ref diff --git a/compiler/ml/predef.ml b/compiler/ml/predef.ml index 6deed6ffa3..1ddb300531 100644 --- a/compiler/ml/predef.ml +++ b/compiler/ml/predef.ml @@ -65,6 +65,8 @@ and ident_promise = ident_create "promise" and ident_uncurried = ident_create "function$" +and ident_tainted = ident_create "tainted$" + type test = For_sure_yes | For_sure_no | NA let type_is_builtin_path_but_option (p : Path.t) : test = @@ -112,6 +114,8 @@ and path_promise = Pident ident_promise and path_uncurried = Pident ident_uncurried +and path_tainted = Pident ident_tainted + let type_int = newgenty (Tconstr (path_int, [], ref Mnil)) and type_char = newgenty (Tconstr (path_char, [], ref Mnil)) diff --git a/compiler/ml/predef.mli b/compiler/ml/predef.mli index 7919b802ee..eccec6d138 100644 --- a/compiler/ml/predef.mli +++ b/compiler/ml/predef.mli @@ -52,6 +52,7 @@ val path_lazy_t : Path.t val path_extension_constructor : Path.t val path_promise : Path.t val path_uncurried : Path.t +val path_tainted : Path.t val path_match_failure : Path.t val path_assert_failure : Path.t diff --git a/compiler/ml/printtyped.ml b/compiler/ml/printtyped.ml index 6bdd794d97..f8d615de5d 100644 --- a/compiler/ml/printtyped.ml +++ b/compiler/ml/printtyped.ml @@ -125,6 +125,11 @@ let arg_label i ppf = function | Optional s -> line i ppf "Optional \"%s\"\n" s | Labelled s -> line i ppf "Labelled \"%s\"\n" s +let arg_label_loc i ppf = function + | Nolabel -> line i ppf "Nolabel\n" + | Optional {txt = s} -> line i ppf "Optional \"%s\"\n" s + | Labelled {txt = s} -> line i ppf "Labelled \"%s\"\n" s + let record_representation i ppf = let open Types in function @@ -658,7 +663,7 @@ and record_field i ppf = function and label_x_expression i ppf (l, e) = line i ppf "\n"; - arg_label (i + 1) ppf l; + arg_label_loc (i + 1) ppf l; match e with | None -> () | Some e -> expression (i + 1) ppf e diff --git a/compiler/ml/translcore.ml b/compiler/ml/translcore.ml index db9624b841..0bc5d8bbda 100644 --- a/compiler/ml/translcore.ml +++ b/compiler/ml/translcore.ml @@ -1019,7 +1019,7 @@ and transl_apply ?(inlined = Default_inline) | _ -> (build_apply lam [] (List.map - (fun (l, x) -> (may_map transl_exp x, Btype.is_optional l)) + (fun (l, x) -> (may_map transl_exp x, Btype.is_optional_loc l)) sargs) : Lambda.lambda) diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index 44bf252d3a..70e4e983ba 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -80,10 +80,24 @@ type error = | Type_params_not_supported of Longident.t | Field_access_on_dict_type exception Error of Location.t * Env.t * error +exception Errors of exn list exception Error_forward of Location.error (* Forward declaration, to be filled in by Typemod.type_module *) +let delayed_typechecking_errors = ref [] + +let add_delayed_error e = + delayed_typechecking_errors := e :: !delayed_typechecking_errors + +let raise_delayed_error_if_exists () = + (* Might have duplicate errors, so remove those. *) + let errors = List.sort_uniq compare !delayed_typechecking_errors in + if errors <> [] then raise (Errors errors) + +let raise_or_continue exn = + if !Clflags.editor_mode then add_delayed_error exn else raise exn + let type_module = ref (fun _env _md -> assert false @@ -261,6 +275,31 @@ let option_none ty loc = let cnone = Env.lookup_constructor lid env in mkexp (Texp_construct (mknoloc lid, cnone, [])) ty loc env +let tainted_expr () = + let lid = Longident.Lident "None" and env = Env.initial_safe_string in + let cnone = Env.lookup_constructor lid env in + { + exp_desc = Texp_construct (mknoloc lid, cnone, []); + exp_type = newconstr Predef.path_tainted []; + exp_loc = Location.none; + exp_env = env; + exp_extra = []; + exp_attributes = [(Location.mknoloc "tainted", PStr [])]; + } + +let tainted_pat expected_type = + let env = Env.initial_safe_string in + { + pat_desc = Tpat_var (Ident.create "tainted$", Location.mknoloc "tainted$"); + pat_type = expected_type; + pat_loc = Location.none; + pat_env = env; + pat_extra = []; + pat_attributes = [(Location.mknoloc "tainted", PStr [])]; + } + +let _ = ignore tainted_pat + let option_some texp = let lid = Longident.Lident "Some" in let csome = Env.lookup_constructor lid Env.initial_safe_string in @@ -299,15 +338,18 @@ let check_optional_attr env ld optional loc = (* unification inside type_pat*) let unify_pat_types loc env ty ty' = try unify env ty ty' with - | Unify trace -> raise (Error (loc, env, Pattern_type_clash trace)) + | Unify trace -> + raise_or_continue (Error (loc, env, Pattern_type_clash trace)) | Tags (l1, l2) -> - raise (Typetexp.Error (loc, env, Typetexp.Variant_tags (l1, l2))) + raise_or_continue + (Typetexp.Error (loc, env, Typetexp.Variant_tags (l1, l2))) (* unification inside type_exp and type_expect *) let unify_exp_types ?type_clash_context loc env ty expected_ty = try unify env ty expected_ty with | Unify trace -> - raise (Error (loc, env, Expr_type_clash (trace, type_clash_context))) + raise_or_continue + (Error (loc, env, Expr_type_clash (trace, type_clash_context))) | Tags (l1, l2) -> raise (Typetexp.Error (loc, env, Typetexp.Variant_tags (l1, l2))) @@ -325,11 +367,13 @@ let unify_pat_types_gadt loc env ty ty' = | Some x -> x in try unify_gadt ~newtype_level env ty ty' with - | Unify trace -> raise (Error (loc, !env, Pattern_type_clash trace)) + | Unify trace -> + raise_or_continue (Error (loc, !env, Pattern_type_clash trace)) | Tags (l1, l2) -> - raise (Typetexp.Error (loc, !env, Typetexp.Variant_tags (l1, l2))) + raise_or_continue + (Typetexp.Error (loc, !env, Typetexp.Variant_tags (l1, l2))) | Unification_recursive_abbrev trace -> - raise (Error (loc, !env, Recursive_local_constraint trace)) + raise_or_continue (Error (loc, !env, Recursive_local_constraint trace)) (* Creating new conjunctive types is not allowed when typing patterns *) @@ -437,7 +481,8 @@ let enter_orpat_variables loc env p1_vs p2_vs = else ( (try unify env t1 t2 with Unify trace -> - raise (Error (loc, env, Or_pattern_type_clash (x1, trace)))); + raise_or_continue + (Error (loc, env, Or_pattern_type_clash (x1, trace)))); (x2, x1) :: unify_vars rem1 rem2) | [], [] -> [] | (x, _, _, _, _) :: _, [] -> raise (Error (loc, env, Orpat_vars (x, []))) @@ -1494,21 +1539,27 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env sp if vars = [] then end_def (); (try unify_pat_types loc !env ty_res record_ty with Unify trace -> - raise + raise_or_continue (Error (label_lid.loc, !env, Label_mismatch (label_lid.txt, trace)))); - type_pat sarg ty_arg (fun arg -> - if vars <> [] then ( - end_def (); - generalize ty_arg; - List.iter generalize vars; - let instantiated tv = - let tv = expand_head !env tv in - (not (is_Tvar tv)) || tv.level <> generic_level - in - if List.exists instantiated vars then - raise - (Error (label_lid.loc, !env, Polymorphic_label label_lid.txt))); - k (label_lid, label, arg, opt)) + try + type_pat sarg ty_arg (fun arg -> + if vars <> [] then ( + end_def (); + generalize ty_arg; + List.iter generalize vars; + let instantiated tv = + let tv = expand_head !env tv in + (not (is_Tvar tv)) || tv.level <> generic_level + in + if List.exists instantiated vars then + raise_or_continue + (Error (label_lid.loc, !env, Polymorphic_label label_lid.txt))); + k (label_lid, label, arg, opt)) + with err -> + if !Clflags.editor_mode then ( + add_delayed_error err; + k (label_lid, label, tainted_pat ty_arg, opt)) + else raise err in let k' k lbl_pat_list = check_recordpat_labels ~get_jsx_component_error_info loc lbl_pat_list @@ -1911,7 +1962,8 @@ let rec type_approx env sexp = let ty1 = approx_type env sty in (try unify env ty ty1 with Unify trace -> - raise (Error (sexp.pexp_loc, env, Expr_type_clash (trace, None)))); + raise_or_continue + (Error (sexp.pexp_loc, env, Expr_type_clash (trace, None)))); ty1 | Pexp_coerce (e, (), sty2) -> let approx_ty_opt = function @@ -1923,7 +1975,8 @@ let rec type_approx env sexp = and ty2 = approx_type env sty2 in (try unify env ty ty1 with Unify trace -> - raise (Error (sexp.pexp_loc, env, Expr_type_clash (trace, None)))); + raise_or_continue + (Error (sexp.pexp_loc, env, Expr_type_clash (trace, None)))); ty2 | _ -> newvar () @@ -2417,6 +2470,9 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg = Rejected) env sexp end_def (); unify_var env (newvar ()) funct.exp_type; + let args_with_loc = + List.map2 (fun (sarg, _) (_, label_exp) -> (sarg, label_exp)) sargs args + in let mk_apply funct args = rue { @@ -2435,8 +2491,8 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg = Rejected) env sexp | _ -> false in - if fully_applied && not is_primitive then rue (mk_apply funct args) - else rue (mk_apply funct args) + if fully_applied && not is_primitive then rue (mk_apply funct args_with_loc) + else rue (mk_apply funct args_with_loc) | Pexp_match (sarg, caselist) -> begin_def (); let arg = type_exp env sarg in @@ -2922,7 +2978,7 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg = Rejected) env sexp let gen = generalizable tv.level arg.exp_type in (try unify_var env tv arg.exp_type with Unify trace -> - raise + raise_or_continue (Error (arg.exp_loc, env, Expr_type_clash (trace, type_clash_context)))); gen) @@ -3317,8 +3373,11 @@ and type_label_exp ?type_clash_context create env loc ty_expected (* Generalize information merged from ty_expected *) generalize_structure ty_arg); if label.lbl_private = Private then - if create then raise (Error (loc, env, Private_type ty_expected)) - else raise (Error (lid.loc, env, Private_label (lid.txt, ty_expected))); + if create then + raise_or_continue (Error (loc, env, Private_type ty_expected)) + else + raise_or_continue + (Error (lid.loc, env, Private_label (lid.txt, ty_expected))); let arg = let snap = if vars = [] then None else Some (Btype.snapshot ()) in let arg = @@ -3528,7 +3587,12 @@ and type_application ?type_clash_context total_app env funct (sargs : sargs) : ( List.map (function | l, None -> (l, None) - | l, Some f -> (l, Some (f ()))) + | l, Some f -> + ( l, + Some + (if !Clflags.editor_mode then + try f () with _ -> tainted_expr () + else f ()) )) (List.rev args), instance env (result_type omitted ty_fun) ) in diff --git a/compiler/ml/typecore.mli b/compiler/ml/typecore.mli index 3aa23756d4..831fbdd51f 100644 --- a/compiler/ml/typecore.mli +++ b/compiler/ml/typecore.mli @@ -19,6 +19,8 @@ open Asttypes open Types open Format +val raise_delayed_error_if_exists : unit -> unit + val is_nonexpansive : Typedtree.expression -> bool val type_binding : @@ -105,6 +107,7 @@ type error = | Type_params_not_supported of Longident.t | Field_access_on_dict_type exception Error of Location.t * Env.t * error +exception Errors of exn list exception Error_forward of Location.error val report_error : Env.t -> formatter -> error -> unit diff --git a/compiler/ml/typedtree.ml b/compiler/ml/typedtree.ml index 626950caec..08d3d8b27b 100644 --- a/compiler/ml/typedtree.ml +++ b/compiler/ml/typedtree.ml @@ -85,7 +85,7 @@ and expression_desc = } | Texp_apply of { funct: expression; - args: (Noloc.arg_label * expression option) list; + args: (arg_label * expression option) list; partial: bool; } | Texp_match of expression * case list * case list * partial diff --git a/compiler/ml/typedtree.mli b/compiler/ml/typedtree.mli index 96da873af0..fd26be62ed 100644 --- a/compiler/ml/typedtree.mli +++ b/compiler/ml/typedtree.mli @@ -148,7 +148,7 @@ and expression_desc = *) | Texp_apply of { funct: expression; - args: (Noloc.arg_label * expression option) list; + args: (arg_label * expression option) list; partial: bool; } (** E0 ~l1:E1 ... ~ln:En diff --git a/tests/analysis_tests/tests-reanalyze/deadcode/expected/deadcode.txt b/tests/analysis_tests/tests-reanalyze/deadcode/expected/deadcode.txt index 121a796eb4..99902b72a5 100644 --- a/tests/analysis_tests/tests-reanalyze/deadcode/expected/deadcode.txt +++ b/tests/analysis_tests/tests-reanalyze/deadcode/expected/deadcode.txt @@ -417,7 +417,7 @@ addValueDeclaration +make Hooks.res:63:6 path:+Hooks.RenderPropRequiresConversion addRecordLabelDeclaration name Hooks.res:1:16 path:+Hooks.vehicle addRecordLabelDeclaration vehicle Hooks.res:4:12 path:+Hooks.props - addValueReference Hooks.res:5:26 --> React.res:134:0 + addValueReference Hooks.res:5:26 --> React.res:145:0 addTypeReference Hooks.res:10:29 --> Hooks.res:1:16 addValueReference Hooks.res:10:29 --> Hooks.res:4:12 addValueReference Hooks.res:10:75 --> Hooks.res:5:7 @@ -1805,7 +1805,7 @@ File References DeadExn.resi -->> DeadRT.res -->> DeadRT.resi -->> - DeadTest.res -->> DeadValueTest.resi, DynamicallyLoadedComponent.res, ImmutableArray.resi, React.res + DeadTest.res -->> React.res, DeadValueTest.resi, DynamicallyLoadedComponent.res, ImmutableArray.resi DeadTestBlacklist.res -->> DeadTestWithInterface.res -->> DeadTypeTest.res -->> @@ -1821,7 +1821,7 @@ File References FirstClassModules.res -->> FirstClassModulesInterface.res -->> FirstClassModulesInterface.resi -->> FirstClassModulesInterface.res - Hooks.res -->> ImportHookDefault.res, ImportHooks.res, React.res + Hooks.res -->> React.res, ImportHookDefault.res, ImportHooks.res IgnoreInterface.res -->> IgnoreInterface.resi -->> ImmutableArray.res -->> diff --git a/tests/analysis_tests/tests/src/EnhanceHover.res b/tests/analysis_tests/tests/src/EnhanceHover.res new file mode 100644 index 0000000000..dc9cbda6ce --- /dev/null +++ b/tests/analysis_tests/tests/src/EnhanceHover.res @@ -0,0 +1,9 @@ +// ^dv+ +let xxxxxxx = [1, 2, 3] +// ^hov + +let xxxxxxxx = [1, 2, 3] +// ^hov + +let xxxxxxxxx = [1, 2, 3] +// ^hov diff --git a/tests/analysis_tests/tests/src/expected/Completion.res.txt b/tests/analysis_tests/tests/src/expected/Completion.res.txt index 1b3f68e11c..0da03d9143 100644 --- a/tests/analysis_tests/tests/src/expected/Completion.res.txt +++ b/tests/analysis_tests/tests/src/expected/Completion.res.txt @@ -1912,6 +1912,26 @@ Path Res "tags": [], "detail": "module Result", "documentation": null + }, { + "label": "RescriptReactErrorBoundary", + "kind": 9, + "tags": [], + "detail": "module RescriptReactErrorBoundary", + "documentation": null, + "data": { + "modulePath": "RescriptReactErrorBoundary", + "filePath": "src/Completion.res" + } + }, { + "label": "RescriptReactRouter", + "kind": 9, + "tags": [], + "detail": "module RescriptReactRouter", + "documentation": null, + "data": { + "modulePath": "RescriptReactRouter", + "filePath": "src/Completion.res" + } }, { "label": "RescriptTools", "kind": 9, @@ -1956,42 +1976,10 @@ Hover src/Completion.res 349:14 {"contents": {"kind": "markdown", "value": "```rescript\nJsxDOM.domProps\n```\n\n---\n\n```\n \n```\n```rescript\ntype JsxDOM.domProps = {\n key?: string,\n children?: Jsx.element,\n ref?: domRef,\n ariaCurrent?: [\n | #date\n | #\"false\"\n | #location\n | #page\n | #step\n | #time\n | #\"true\"\n ],\n ariaDetails?: string,\n ariaDisabled?: bool,\n ariaHidden?: bool,\n ariaInvalid?: [#\"false\" | #grammar | #spelling | #\"true\"],\n ariaKeyshortcuts?: string,\n ariaLabel?: string,\n ariaRoledescription?: string,\n ariaAutocomplete?: [#both | #inline | #list | #none],\n ariaChecked?: [#\"false\" | #mixed | #\"true\"],\n ariaExpanded?: bool,\n ariaHaspopup?: [\n | #dialog\n | #\"false\"\n | #grid\n | #listbox\n | #menu\n | #tree\n | #\"true\"\n ],\n ariaLevel?: int,\n ariaModal?: bool,\n ariaMultiline?: bool,\n ariaMultiselectable?: bool,\n ariaOrientation?: [#horizontal | #undefined | #vertical],\n ariaPlaceholder?: string,\n ariaPressed?: [#\"false\" | #mixed | #\"true\"],\n ariaReadonly?: bool,\n ariaRequired?: bool,\n ariaSelected?: bool,\n ariaSort?: string,\n ariaValuemax?: float,\n ariaValuemin?: float,\n ariaValuenow?: float,\n ariaValuetext?: string,\n ariaAtomic?: bool,\n ariaBusy?: bool,\n ariaLive?: [#assertive | #off | #polite | #rude],\n ariaRelevant?: string,\n ariaDropeffect?: [\n | #copy\n | #execute\n | #link\n | #move\n | #none\n | #popup\n ],\n ariaGrabbed?: bool,\n ariaActivedescendant?: string,\n ariaColcount?: int,\n ariaColindex?: int,\n ariaColspan?: int,\n ariaControls?: string,\n ariaDescribedby?: string,\n ariaErrormessage?: string,\n ariaFlowto?: string,\n ariaLabelledby?: string,\n ariaOwns?: string,\n ariaPosinset?: int,\n ariaRowcount?: int,\n ariaRowindex?: int,\n ariaRowspan?: int,\n ariaSetsize?: int,\n defaultChecked?: bool,\n defaultValue?: string,\n accessKey?: string,\n capture?: [#environment | #user],\n className?: string,\n contentEditable?: bool,\n contextMenu?: string,\n dataTestId?: string,\n dir?: string,\n draggable?: bool,\n hidden?: bool,\n id?: string,\n inert?: bool,\n lang?: string,\n popover?: popover,\n popoverTarget?: string,\n popoverTargetAction?: popoverTargetAction,\n role?: string,\n style?: style,\n spellCheck?: bool,\n tabIndex?: int,\n title?: string,\n itemID?: string,\n itemProp?: string,\n itemRef?: string,\n itemScope?: bool,\n itemType?: string,\n accept?: string,\n acceptCharset?: string,\n action?: string,\n allowFullScreen?: bool,\n alt?: string,\n as_?: string,\n async?: bool,\n autoComplete?: string,\n autoCapitalize?: string,\n autoFocus?: bool,\n autoPlay?: bool,\n challenge?: string,\n charSet?: string,\n checked?: bool,\n cite?: string,\n crossOrigin?: string,\n cols?: int,\n colSpan?: int,\n content?: string,\n controls?: bool,\n coords?: string,\n data?: string,\n dateTime?: string,\n default?: bool,\n defer?: bool,\n disabled?: bool,\n download?: string,\n encType?: string,\n form?: string,\n formAction?: string,\n formTarget?: string,\n formMethod?: string,\n headers?: string,\n height?: string,\n high?: int,\n href?: string,\n hrefLang?: string,\n htmlFor?: string,\n httpEquiv?: string,\n icon?: string,\n inputMode?: string,\n integrity?: string,\n keyType?: string,\n kind?: string,\n label?: string,\n list?: string,\n loading?: [#eager | #lazy],\n loop?: bool,\n low?: int,\n manifest?: string,\n max?: string,\n maxLength?: int,\n media?: string,\n mediaGroup?: string,\n method?: string,\n min?: string,\n minLength?: int,\n multiple?: bool,\n muted?: bool,\n name?: string,\n nonce?: string,\n noValidate?: bool,\n open_?: bool,\n optimum?: int,\n pattern?: string,\n placeholder?: string,\n playsInline?: bool,\n poster?: string,\n preload?: string,\n radioGroup?: string,\n readOnly?: bool,\n rel?: string,\n required?: bool,\n reversed?: bool,\n rows?: int,\n rowSpan?: int,\n sandbox?: string,\n scope?: string,\n scoped?: bool,\n scrolling?: string,\n selected?: bool,\n shape?: string,\n size?: int,\n sizes?: string,\n span?: int,\n src?: string,\n srcDoc?: string,\n srcLang?: string,\n srcSet?: string,\n start?: int,\n step?: float,\n summary?: string,\n target?: string,\n type_?: string,\n useMap?: string,\n value?: string,\n width?: string,\n wrap?: string,\n onCopy?: JsxEvent.Clipboard.t => unit,\n onCut?: JsxEvent.Clipboard.t => unit,\n onPaste?: JsxEvent.Clipboard.t => unit,\n onCompositionEnd?: JsxEvent.Composition.t => unit,\n onCompositionStart?: JsxEvent.Composition.t => unit,\n onCompositionUpdate?: JsxEvent.Composition.t => unit,\n onKeyDown?: JsxEvent.Keyboard.t => unit,\n onKeyPress?: JsxEvent.Keyboard.t => unit,\n onKeyUp?: JsxEvent.Keyboard.t => unit,\n onFocus?: JsxEvent.Focus.t => unit,\n onBlur?: JsxEvent.Focus.t => unit,\n onBeforeInput?: JsxEvent.Form.t => unit,\n onChange?: JsxEvent.Form.t => unit,\n onInput?: JsxEvent.Form.t => unit,\n onReset?: JsxEvent.Form.t => unit,\n onSubmit?: JsxEvent.Form.t => unit,\n onInvalid?: JsxEvent.Form.t => unit,\n onClick?: JsxEvent.Mouse.t => unit,\n onContextMenu?: JsxEvent.Mouse.t => unit,\n onDoubleClick?: JsxEvent.Mouse.t => unit,\n onDrag?: JsxEvent.Mouse.t => unit,\n onDragEnd?: JsxEvent.Mouse.t => unit,\n onDragEnter?: JsxEvent.Mouse.t => unit,\n onDragExit?: JsxEvent.Mouse.t => unit,\n onDragLeave?: JsxEvent.Mouse.t => unit,\n onDragOver?: JsxEvent.Mouse.t => unit,\n onDragStart?: JsxEvent.Mouse.t => unit,\n onDrop?: JsxEvent.Mouse.t => unit,\n onMouseDown?: JsxEvent.Mouse.t => unit,\n onMouseEnter?: JsxEvent.Mouse.t => unit,\n onMouseLeave?: JsxEvent.Mouse.t => unit,\n onMouseMove?: JsxEvent.Mouse.t => unit,\n onMouseOut?: JsxEvent.Mouse.t => unit,\n onMouseOver?: JsxEvent.Mouse.t => unit,\n onMouseUp?: JsxEvent.Mouse.t => unit,\n onSelect?: JsxEvent.Selection.t => unit,\n onTouchCancel?: JsxEvent.Touch.t => unit,\n onTouchEnd?: JsxEvent.Touch.t => unit,\n onTouchMove?: JsxEvent.Touch.t => unit,\n onTouchStart?: JsxEvent.Touch.t => unit,\n onPointerOver?: JsxEvent.Pointer.t => unit,\n onPointerEnter?: JsxEvent.Pointer.t => unit,\n onPointerDown?: JsxEvent.Pointer.t => unit,\n onPointerMove?: JsxEvent.Pointer.t => unit,\n onPointerUp?: JsxEvent.Pointer.t => unit,\n onPointerCancel?: JsxEvent.Pointer.t => unit,\n onPointerOut?: JsxEvent.Pointer.t => unit,\n onPointerLeave?: JsxEvent.Pointer.t => unit,\n onGotPointerCapture?: JsxEvent.Pointer.t => unit,\n onLostPointerCapture?: JsxEvent.Pointer.t => unit,\n onScroll?: JsxEvent.UI.t => unit,\n onWheel?: JsxEvent.Wheel.t => unit,\n onAbort?: JsxEvent.Media.t => unit,\n onCanPlay?: JsxEvent.Media.t => unit,\n onCanPlayThrough?: JsxEvent.Media.t => unit,\n onDurationChange?: JsxEvent.Media.t => unit,\n onEmptied?: JsxEvent.Media.t => unit,\n onEncrypted?: JsxEvent.Media.t => unit,\n onEnded?: JsxEvent.Media.t => unit,\n onError?: JsxEvent.Media.t => unit,\n onLoadedData?: JsxEvent.Media.t => unit,\n onLoadedMetadata?: JsxEvent.Media.t => unit,\n onLoadStart?: JsxEvent.Media.t => unit,\n onPause?: JsxEvent.Media.t => unit,\n onPlay?: JsxEvent.Media.t => unit,\n onPlaying?: JsxEvent.Media.t => unit,\n onProgress?: JsxEvent.Media.t => unit,\n onRateChange?: JsxEvent.Media.t => unit,\n onSeeked?: JsxEvent.Media.t => unit,\n onSeeking?: JsxEvent.Media.t => unit,\n onStalled?: JsxEvent.Media.t => unit,\n onSuspend?: JsxEvent.Media.t => unit,\n onTimeUpdate?: JsxEvent.Media.t => unit,\n onVolumeChange?: JsxEvent.Media.t => unit,\n onWaiting?: JsxEvent.Media.t => unit,\n onLoad?: JsxEvent.Image.t => unit,\n onAnimationStart?: JsxEvent.Animation.t => unit,\n onAnimationEnd?: JsxEvent.Animation.t => unit,\n onAnimationIteration?: JsxEvent.Animation.t => unit,\n onTransitionEnd?: JsxEvent.Transition.t => unit,\n accentHeight?: string,\n accumulate?: string,\n additive?: string,\n alignmentBaseline?: string,\n allowReorder?: string,\n alphabetic?: string,\n amplitude?: string,\n arabicForm?: string,\n ascent?: string,\n attributeName?: string,\n attributeType?: string,\n autoReverse?: string,\n azimuth?: string,\n baseFrequency?: string,\n baseProfile?: string,\n baselineShift?: string,\n bbox?: string,\n begin?: string,\n begin_?: string,\n bias?: string,\n by?: string,\n calcMode?: string,\n capHeight?: string,\n clip?: string,\n clipPath?: string,\n clipPathUnits?: string,\n clipRule?: string,\n colorInterpolation?: string,\n colorInterpolationFilters?: string,\n colorProfile?: string,\n colorRendering?: string,\n contentScriptType?: string,\n contentStyleType?: string,\n cursor?: string,\n cx?: string,\n cy?: string,\n d?: string,\n decelerate?: string,\n descent?: string,\n diffuseConstant?: string,\n direction?: string,\n display?: string,\n divisor?: string,\n dominantBaseline?: string,\n dur?: string,\n dx?: string,\n dy?: string,\n edgeMode?: string,\n elevation?: string,\n enableBackground?: string,\n end?: string,\n end_?: string,\n exponent?: string,\n externalResourcesRequired?: string,\n fill?: string,\n fillOpacity?: string,\n fillRule?: string,\n filter?: string,\n filterRes?: string,\n filterUnits?: string,\n floodColor?: string,\n floodOpacity?: string,\n focusable?: string,\n fontFamily?: string,\n fontSize?: string,\n fontSizeAdjust?: string,\n fontStretch?: string,\n fontStyle?: string,\n fontVariant?: string,\n fontWeight?: string,\n fomat?: string,\n from?: string,\n fx?: string,\n fy?: string,\n g1?: string,\n g2?: string,\n glyphName?: string,\n glyphOrientationHorizontal?: string,\n glyphOrientationVertical?: string,\n glyphRef?: string,\n gradientTransform?: string,\n gradientUnits?: string,\n hanging?: string,\n horizAdvX?: string,\n horizOriginX?: string,\n ideographic?: string,\n imageRendering?: string,\n in_?: string,\n in2?: string,\n intercept?: string,\n k?: string,\n k1?: string,\n k2?: string,\n k3?: string,\n k4?: string,\n kernelMatrix?: string,\n kernelUnitLength?: string,\n kerning?: string,\n keyPoints?: string,\n keySplines?: string,\n keyTimes?: string,\n lengthAdjust?: string,\n letterSpacing?: string,\n lightingColor?: string,\n limitingConeAngle?: string,\n local?: string,\n markerEnd?: string,\n markerHeight?: string,\n markerMid?: string,\n markerStart?: string,\n markerUnits?: string,\n markerWidth?: string,\n mask?: string,\n maskContentUnits?: string,\n maskUnits?: string,\n mathematical?: string,\n mode?: string,\n numOctaves?: string,\n offset?: string,\n opacity?: string,\n operator?: string,\n order?: string,\n orient?: string,\n orientation?: string,\n origin?: string,\n overflow?: string,\n overflowX?: string,\n overflowY?: string,\n overlinePosition?: string,\n overlineThickness?: string,\n paintOrder?: string,\n panose1?: string,\n pathLength?: string,\n patternContentUnits?: string,\n patternTransform?: string,\n patternUnits?: string,\n pointerEvents?: string,\n points?: string,\n pointsAtX?: string,\n pointsAtY?: string,\n pointsAtZ?: string,\n preserveAlpha?: string,\n preserveAspectRatio?: string,\n primitiveUnits?: string,\n r?: string,\n radius?: string,\n refX?: string,\n refY?: string,\n renderingIntent?: string,\n repeatCount?: string,\n repeatDur?: string,\n requiredExtensions?: string,\n requiredFeatures?: string,\n restart?: string,\n result?: string,\n rotate?: string,\n rx?: string,\n ry?: string,\n scale?: string,\n seed?: string,\n shapeRendering?: string,\n slope?: string,\n spacing?: string,\n specularConstant?: string,\n specularExponent?: string,\n speed?: string,\n spreadMethod?: string,\n startOffset?: string,\n stdDeviation?: string,\n stemh?: string,\n stemv?: string,\n stitchTiles?: string,\n stopColor?: string,\n stopOpacity?: string,\n strikethroughPosition?: string,\n strikethroughThickness?: string,\n string?: string,\n stroke?: string,\n strokeDasharray?: string,\n strokeDashoffset?: string,\n strokeLinecap?: string,\n strokeLinejoin?: string,\n strokeMiterlimit?: string,\n strokeOpacity?: string,\n strokeWidth?: string,\n surfaceScale?: string,\n systemLanguage?: string,\n tableValues?: string,\n targetX?: string,\n targetY?: string,\n textAnchor?: string,\n textDecoration?: string,\n textLength?: string,\n textRendering?: string,\n to?: string,\n to_?: string,\n transform?: string,\n u1?: string,\n u2?: string,\n underlinePosition?: string,\n underlineThickness?: string,\n unicode?: string,\n unicodeBidi?: string,\n unicodeRange?: string,\n unitsPerEm?: string,\n vAlphabetic?: string,\n vHanging?: string,\n vIdeographic?: string,\n vMathematical?: string,\n values?: string,\n vectorEffect?: string,\n version?: string,\n vertAdvX?: string,\n vertAdvY?: string,\n vertOriginX?: string,\n vertOriginY?: string,\n viewBox?: string,\n viewTarget?: string,\n visibility?: string,\n widths?: string,\n wordSpacing?: string,\n writingMode?: string,\n x?: string,\n x1?: string,\n x2?: string,\n xChannelSelector?: string,\n xHeight?: string,\n xlinkActuate?: string,\n xlinkArcrole?: string,\n xlinkHref?: string,\n xlinkRole?: string,\n xlinkShow?: string,\n xlinkTitle?: string,\n xlinkType?: string,\n xmlns?: string,\n xmlnsXlink?: string,\n xmlBase?: string,\n xmlLang?: string,\n xmlSpace?: string,\n y?: string,\n y1?: string,\n y2?: string,\n yChannelSelector?: string,\n z?: string,\n zoomAndPan?: string,\n about?: string,\n datatype?: string,\n inlist?: string,\n prefix?: string,\n property?: string,\n resource?: string,\n typeof?: string,\n vocab?: string,\n dangerouslySetInnerHTML?: {\"__html\": string},\n suppressContentEditableWarning?: bool,\n}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxDOM.res%22%2C38%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype Jsx.element\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Jsx.res%22%2C24%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype domRef\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxDOM.res%22%2C25%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype popover =\n | @as(\"auto\") Auto\n | @as(\"manual\") Manual\n | @as(\"hint\") Hint\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxDOM.res%22%2C29%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype popoverTargetAction =\n | @as(\"toggle\") Toggle\n | @as(\"show\") Show\n | @as(\"hide\") Hide\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxDOM.res%22%2C33%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype style = JsxDOMStyle.t\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxDOM.res%22%2C24%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.Clipboard.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C95%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.Composition.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C107%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.Keyboard.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C118%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.Focus.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C142%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.Form.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C154%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.Mouse.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C163%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.Selection.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C244%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.Touch.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C253%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.Pointer.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C194%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.UI.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C278%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.Wheel.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C291%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.Media.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C305%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.Image.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C314%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.Animation.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C323%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype JsxEvent.Transition.t = synthetic\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxEvent.res%22%2C336%2C2%5D)\n"}} Hover src/Completion.res 352:17 -Nothing at that position. Now trying to use completion. -posCursor:[352:17] posNoWhite:[352:16] Found expr:[352:11->352:35] -Pexp_send age[352:30->352:33] e:[352:11->352:28] -posCursor:[352:17] posNoWhite:[352:16] Found expr:[352:11->352:28] -Pexp_ident FAO.forAutoObject:[352:11->352:28] -Completable: Cpath Value[FAO, forAutoObject] -Raw opens: 2 Shadow.B.place holder ... Shadow.A.place holder -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 3 Stdlib Completion Completion -ContextPath Value[FAO, forAutoObject] -Path FAO.forAutoObject -Raw opens: 2 Shadow.B.place holder ... Shadow.A.place holder -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -{"contents": {"kind": "markdown", "value": "```rescript\n{\"age\": int, \"forAutoLabel\": FAR.forAutoRecord}\n```"}} +null Hover src/Completion.res 355:17 -Nothing at that position. Now trying to use completion. -posCursor:[355:17] posNoWhite:[355:16] Found expr:[355:11->355:22] -Pexp_apply ...[355:11->355:13] (~opt1355:15->355:19=...[355:20->355:21]) -Completable: CnamedArg(Value[ff], opt1, [opt1]) -Raw opens: 2 Shadow.B.place holder ... Shadow.A.place holder -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 3 Stdlib Completion Completion -ContextPath Value[ff] -Path ff -Found type for function ( - ~opt1: int=?, - ~a: int, - ~b: int, - unit, - ~opt2: int=?, - unit, - ~c: int, -) => int -{"contents": {"kind": "markdown", "value": "```rescript\noption\n```"}} +null Complete src/Completion.res 358:23 posCursor:[358:23] posNoWhite:[358:22] Found expr:[0:-1->358:23] diff --git a/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt b/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt index 8755e16516..81d1536ae9 100644 --- a/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt +++ b/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt @@ -966,17 +966,5 @@ Path ReactDOM.Client.Root. }] Hover src/CompletionInferValues.res 160:27 -Nothing at that position. Now trying to use completion. -posCursor:[160:27] posNoWhite:[160:26] Found expr:[160:25->160:28] -Pexp_ident res:[160:25->160:28] -Completable: Cpath Value[res] -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -ContextPath Value[res] -Path res -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -ContextPath Value[res] -Path res -{"contents": {"kind": "markdown", "value": "```rescript\nint\n```"}} +null diff --git a/tests/analysis_tests/tests/src/expected/EnhanceHover.res.txt b/tests/analysis_tests/tests/src/expected/EnhanceHover.res.txt new file mode 100644 index 0000000000..931b437f6a --- /dev/null +++ b/tests/analysis_tests/tests/src/expected/EnhanceHover.res.txt @@ -0,0 +1,10 @@ + +Hover src/EnhanceHover.res 1:4 +{"contents": {"kind": "markdown", "value": "```rescript\narray\n```"}} + +Hover src/EnhanceHover.res 4:15 +{"contents": {"kind": "markdown", "value": "```rescript\narray\n```"}} + +Hover src/EnhanceHover.res 7:17 +{"contents": {"kind": "markdown", "value": "```rescript\nint\n```"}} + diff --git a/tests/analysis_tests/tests/src/expected/Fragment.res.txt b/tests/analysis_tests/tests/src/expected/Fragment.res.txt index 3b67cf3a42..d897610801 100644 --- a/tests/analysis_tests/tests/src/expected/Fragment.res.txt +++ b/tests/analysis_tests/tests/src/expected/Fragment.res.txt @@ -2,16 +2,5 @@ Hover src/Fragment.res 6:19 {"contents": {"kind": "markdown", "value": "```rescript\nReact.component>\n```\n\n---\n\n```\n \n```\n```rescript\ntype React.component<'props> = Jsx.component<'props>\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22React.res%22%2C12%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype SectionHeader.props<'children> = {children: 'children}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Fragment.res%22%2C1%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype React.element = Jsx.element\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22React.res%22%2C0%2C0%5D)\n"}} Hover src/Fragment.res 9:56 -Nothing at that position. Now trying to use completion. -posCursor:[9:56] posNoWhite:[9:55] Found expr:[9:10->9:67] -posCursor:[9:56] posNoWhite:[9:55] Found expr:[9:13->9:67] -posCursor:[9:56] posNoWhite:[9:55] Found expr:[9:13->9:66] -JSX 9:26] > _children:9:26 -posCursor:[9:56] posNoWhite:[9:55] Found expr:__ghost__[9:10->9:67] -Pexp_construct []:__ghost__[9:10->9:67] None -Completable: Cexpression CTypeAtPos()=[]->variantPayload::::($1) -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -ContextPath CTypeAtPos() -null +{"contents": {"kind": "markdown", "value": "```rescript\nReact.element\n```"}} diff --git a/tests/analysis_tests/tests/src/expected/Hover.res.txt b/tests/analysis_tests/tests/src/expected/Hover.res.txt index 8d692baed4..6a1ef98a7d 100644 --- a/tests/analysis_tests/tests/src/expected/Hover.res.txt +++ b/tests/analysis_tests/tests/src/expected/Hover.res.txt @@ -19,7 +19,7 @@ heuristic for: [makeProps, make, createElement], give the loc of `make` {"contents": {"kind": "markdown", "value": "```rescript\nint\n```"}} Hover src/Hover.res 33:4 -{"contents": {"kind": "markdown", "value": "```rescript\nunit => int\n```\n---\nDoc comment for functionWithTypeAnnotation"}} +{"contents": {"kind": "markdown", "value": "```rescript\nunit => int\n```"}} Hover src/Hover.res 37:13 {"contents": {"kind": "markdown", "value": "```rescript\nstring\n```"}} @@ -49,16 +49,10 @@ Hover src/Hover.res 77:7 {"contents": {"kind": "markdown", "value": "```rescript\nmodule A: {\n let x: int\n}\n```"}} Hover src/Hover.res 91:10 -Nothing at that position. Now trying to use completion. -posCursor:[91:10] posNoWhite:[91:8] Found expr:[88:3->91:9] -JSX 88:7] > _children:88:7 null Hover src/Hover.res 98:10 -Nothing at that position. Now trying to use completion. -posCursor:[98:10] posNoWhite:[98:9] Found expr:[95:3->98:10] -JSX 95:8] > _children:95:8 -null +{"contents": {"kind": "markdown", "value": "```rescript\nReact.element\n```"}} Hover src/Hover.res 103:25 {"contents": {"kind": "markdown", "value": "```rescript\nfloat\n```"}} @@ -73,12 +67,7 @@ Hover src/Hover.res 119:25 {"contents": {"kind": "markdown", "value": "```rescript\nAA.cond<([< #str(string)] as 'a)> => AA.cond<'a>\n```\n\n---\n\n```\n \n```\n```rescript\ntype AA.cond<'a> = 'a\n constraint 'a = [< #str(string)]\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C110%2C2%5D)\n"}} Hover src/Hover.res 122:3 -Nothing at that position. Now trying to use completion. -Attribute id:live:[122:0->122:5] label:live -Completable: Cdecorator(live) -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -{"contents": {"kind": "markdown", "value": "The `@live` decorator is for reanalyze, a static analysis tool for ReScript that can do dead code analysis.\n\n`@live` tells the dead code analysis that the value should be considered live, even though it might appear to be dead. This is typically used in case of FFI where there are indirect ways to access values. It can be added to everything that could otherwise be considered unused by the dead code analysis - values, functions, arguments, records, individual record fields, and so on.\n\n[Read more and see examples in the documentation](https://rescript-lang.org/syntax-lookup#live-decorator).\n\nHint: Did you know you can run an interactive code analysis in your project by running the command `> ReScript: Start Code Analyzer`? Try it!"}} +null Hover src/Hover.res 125:4 {"contents": {"kind": "markdown", "value": "```rescript\nunit => unit => int\n```"}} @@ -244,20 +233,10 @@ Hover src/Hover.res 197:4 {"contents": {"kind": "markdown", "value": "```rescript\nCompV4.props => React.element\n```\n\n---\n\n```\n \n```\n```rescript\ntype CompV4.props<'n, 's> = {n?: 'n, s: 's}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C190%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype React.element = Jsx.element\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22React.res%22%2C0%2C0%5D)\n"}} Hover src/Hover.res 202:16 -{"contents": {"kind": "markdown", "value": "```rescript\nuseR\n```\n\n---\n\n```\n \n```\n```rescript\ntype useR = {x: int, y: list>>}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C200%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype r<'a> = {i: 'a, f: float}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C101%2C0%5D)\n"}} +{"contents": {"kind": "markdown", "value": "```rescript\nuseR\n```"}} Hover src/Hover.res 210:13 -Nothing at that position. Now trying to use completion. -posCursor:[210:13] posNoWhite:[210:12] Found expr:[210:11->210:14] -Pexp_ident usr:[210:11->210:14] -Completable: Cpath Value[usr] -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -ContextPath Value[usr] -Path usr -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -{"contents": {"kind": "markdown", "value": "```rescript\nuseR\n```\n\n---\n\n```\n \n```\n```rescript\ntype useR = {x: int, y: list>>}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C200%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype r<'a> = {i: 'a, f: float}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C101%2C0%5D)\n"}} +null Hover src/Hover.res 230:20 {"contents": {"kind": "markdown", "value": "```rescript\nint\n```\n---\n More Stuff "}} @@ -266,23 +245,7 @@ Hover src/Hover.res 233:17 {"contents": {"kind": "markdown", "value": "```rescript\nint\n```\n---\n More Stuff "}} Hover src/Hover.res 245:6 -Nothing at that position. Now trying to use completion. -posCursor:[245:6] posNoWhite:[245:5] Found expr:[245:3->245:14] -Pexp_field [245:3->245:4] someField:[245:5->245:14] -Completable: Cpath Value[x].someField -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -ContextPath Value[x].someField -ContextPath Value[x] -Path x -ContextPath Value[x]->someField -ContextPath Value[x] -Path x -CPPipe pathFromEnv: found:true -Path Hover.someField -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -{"contents": {"kind": "markdown", "value": " Mighty fine field here. \n\n```rescript\nbool\n```"}} +null Hover src/Hover.res 248:19 {"contents": {"kind": "markdown", "value": "```rescript\nbool\n```\n---\n Mighty fine field here. "}} @@ -291,34 +254,10 @@ Hover src/Hover.res 253:20 {"contents": {"kind": "markdown", "value": "```rescript\nvariant\n```\n\n---\n\n```\n \n```\n```rescript\ntype variant = CoolVariant | OtherCoolVariant\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C251%2C0%5D)\n\n---\n```rescript\nCoolVariant\n```\n---\n Cool variant! "}} Hover src/Hover.res 257:23 -Nothing at that position. Now trying to use completion. -posCursor:[257:23] posNoWhite:[257:22] Found expr:[257:22->257:25] -Pexp_ident fff:[257:22->257:25] -Completable: Cpath Value[fff] -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -ContextPath Value[fff] -Path fff -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -ContextPath string -{"contents": {"kind": "markdown", "value": "```rescript\nstring\n```"}} +null Hover src/Hover.res 260:33 -Nothing at that position. Now trying to use completion. -posCursor:[260:33] posNoWhite:[260:32] Found expr:[260:31->260:40] -Pexp_ident someField:[260:31->260:40] -Completable: Cpath Value[someField] -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -ContextPath Value[someField] -Path someField -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -ContextPath CPatternPath(Value[x])->recordField(someField) -ContextPath Value[x] -Path x -{"contents": {"kind": "markdown", "value": "```rescript\nbool\n```"}} +null Hover src/Hover.res 263:8 {"contents": {"kind": "markdown", "value": "\n [`Belt.Array`]()\n\n **mutable array**: Utilities functions\n\n```rescript\nmodule Array: {\n module Id\n module Array\n module SortArray\n module MutableQueue\n module MutableStack\n module List\n module Range\n module Set\n module Map\n module MutableSet\n module MutableMap\n module HashSet\n module HashMap\n module Option\n module Result\n module Int\n module Float\n}\n```"}} diff --git a/tests/analysis_tests/tests/src/expected/InlayHint.res.txt b/tests/analysis_tests/tests/src/expected/InlayHint.res.txt index aad649db3b..68d69c9c81 100644 --- a/tests/analysis_tests/tests/src/expected/InlayHint.res.txt +++ b/tests/analysis_tests/tests/src/expected/InlayHint.res.txt @@ -17,18 +17,6 @@ Inlay Hint src/InlayHint.res 1:34 "kind": 1, "paddingLeft": true, "paddingRight": false -}, { - "position": {"line": 26, "character": 23}, - "label": ": (string, string)", - "kind": 1, - "paddingLeft": true, - "paddingRight": false -}, { - "position": {"line": 18, "character": 9}, - "label": ": string", - "kind": 1, - "paddingLeft": true, - "paddingRight": false }, { "position": {"line": 16, "character": 9}, "label": ": (string, string)", diff --git a/tests/analysis_tests/tests/src/expected/Jsx2.res.txt b/tests/analysis_tests/tests/src/expected/Jsx2.res.txt index 76c895c556..b945c4609e 100644 --- a/tests/analysis_tests/tests/src/expected/Jsx2.res.txt +++ b/tests/analysis_tests/tests/src/expected/Jsx2.res.txt @@ -379,7 +379,17 @@ Package opens Stdlib.place holder Pervasives.JsxModules.place holder Resolved opens 1 Stdlib ContextPath Type[ReactDOMR] Path ReactDOMR -[] +[{ + "label": "ReactDOMRe", + "kind": 9, + "tags": [], + "detail": "module ReactDOMRe", + "documentation": null, + "data": { + "modulePath": "ReactDOMRe", + "filePath": "src/Jsx2.res" + } + }] Complete src/Jsx2.res 102:21 posCursor:[102:21] posNoWhite:[102:20] Found expr:[102:13->102:21] @@ -523,28 +533,8 @@ Path Nested. }] Hover src/Jsx2.res 162:12 -Nothing at that position. Now trying to use completion. -posCursor:[162:12] posNoWhite:[162:11] Found expr:[162:3->162:21] -posCursor:[162:12] posNoWhite:[162:11] Found expr:[162:6->162:21] -posCursor:[162:12] posNoWhite:[162:11] Found expr:[162:6->162:20] -JSX 162:10] age[162:11->162:14]=...[162:15->162:17]> _children:162:18 -Completable: Cjsx([Comp], age, [age]) -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -Path Comp.make -{"contents": {"kind": "markdown", "value": "```rescript\nint\n```"}} +{"contents": {"kind": "markdown", "value": "```rescript\nReact.element\n```"}} Hover src/Jsx2.res 167:16 -Nothing at that position. Now trying to use completion. -posCursor:[167:16] posNoWhite:[167:15] Found expr:[167:3->167:30] -posCursor:[167:16] posNoWhite:[167:15] Found expr:[167:7->167:30] -posCursor:[167:16] posNoWhite:[167:15] Found expr:[167:7->167:25] -posCursor:[167:16] posNoWhite:[167:15] Found expr:[167:10->167:25] -posCursor:[167:16] posNoWhite:[167:15] Found expr:[167:10->167:24] -JSX 167:14] age[167:15->167:18]=...[167:19->167:21]> _children:167:22 -Completable: Cjsx([Comp], age, [age]) -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -Path Comp.make -{"contents": {"kind": "markdown", "value": "```rescript\nint\n```"}} +{"contents": {"kind": "markdown", "value": "```rescript\nReact.element\n```"}} diff --git a/tests/analysis_tests/tests/src/expected/NestedRecords.res.txt b/tests/analysis_tests/tests/src/expected/NestedRecords.res.txt index db012ca3c9..efc1d78177 100644 --- a/tests/analysis_tests/tests/src/expected/NestedRecords.res.txt +++ b/tests/analysis_tests/tests/src/expected/NestedRecords.res.txt @@ -1,118 +1,12 @@ Hover src/NestedRecords.res 17:5 -Nothing at that position. Now trying to use completion. -posCursor:[17:5] posNoWhite:[17:4] Found expr:[17:3->17:10] -Pexp_ident options:[17:3->17:10] -Completable: Cpath Value[options] -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -ContextPath Value[options] -Path options -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -{"contents": {"kind": "markdown", "value": "```rescript\noptions\n```\n\n---\n\n```\n \n```\n```rescript\ntype options = {\n extra: {name: string, superExtra: {age: int}},\n}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22NestedRecords.res%22%2C1%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype options.extra = {name: string, superExtra: {age: int}}\n```\n"}} +null Hover src/NestedRecords.res 20:13 -Nothing at that position. Now trying to use completion. -posCursor:[20:13] posNoWhite:[20:12] Found expr:[20:3->20:16] -Pexp_field [20:3->20:10] extra:[20:11->20:16] -Completable: Cpath Value[options].extra -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -ContextPath Value[options].extra -ContextPath Value[options] -Path options -ContextPath Value[options]->extra -ContextPath Value[options] -Path options -CPPipe pathFromEnv: found:true -Path NestedRecords.extra -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -{"contents": {"kind": "markdown", "value": "```rescript\ntype options.extra = {name: string, superExtra: {age: int}}\n```"}} +null Hover src/NestedRecords.res 23:26 -Nothing at that position. Now trying to use completion. -posCursor:[23:26] posNoWhite:[23:25] Found expr:[23:3->23:27] -Pexp_field [23:3->23:16] superExtra:[23:17->23:27] -Completable: Cpath Value[options].extra.superExtra -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -ContextPath Value[options].extra.superExtra -ContextPath Value[options].extra -ContextPath Value[options] -Path options -ContextPath Value[options]->extra -ContextPath Value[options] -Path options -CPPipe pathFromEnv: found:true -Path NestedRecords.extra -ContextPath Value[options].extra->superExtra -ContextPath Value[options].extra -ContextPath Value[options] -Path options -ContextPath Value[options]->extra -ContextPath Value[options] -Path options -CPPipe pathFromEnv: found:true -Path NestedRecords.extra -CPPipe pathFromEnv: found:true -Path NestedRecords.superExtra -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -{"contents": {"kind": "markdown", "value": "```rescript\ntype options.extra.superExtra = {age: int}\n```"}} +null Hover src/NestedRecords.res 26:29 -Nothing at that position. Now trying to use completion. -posCursor:[26:29] posNoWhite:[26:28] Found expr:[26:3->26:31] -Pexp_field [26:3->26:27] age:[26:28->26:31] -Completable: Cpath Value[options].extra.superExtra.age -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -ContextPath Value[options].extra.superExtra.age -ContextPath Value[options].extra.superExtra -ContextPath Value[options].extra -ContextPath Value[options] -Path options -ContextPath Value[options]->extra -ContextPath Value[options] -Path options -CPPipe pathFromEnv: found:true -Path NestedRecords.extra -ContextPath Value[options].extra->superExtra -ContextPath Value[options].extra -ContextPath Value[options] -Path options -ContextPath Value[options]->extra -ContextPath Value[options] -Path options -CPPipe pathFromEnv: found:true -Path NestedRecords.extra -CPPipe pathFromEnv: found:true -Path NestedRecords.superExtra -ContextPath Value[options].extra.superExtra->age -ContextPath Value[options].extra.superExtra -ContextPath Value[options].extra -ContextPath Value[options] -Path options -ContextPath Value[options]->extra -ContextPath Value[options] -Path options -CPPipe pathFromEnv: found:true -Path NestedRecords.extra -ContextPath Value[options].extra->superExtra -ContextPath Value[options].extra -ContextPath Value[options] -Path options -ContextPath Value[options]->extra -ContextPath Value[options] -Path options -CPPipe pathFromEnv: found:true -Path NestedRecords.extra -CPPipe pathFromEnv: found:true -Path NestedRecords.superExtra -CPPipe pathFromEnv: found:true -Path NestedRecords.age -Package opens Stdlib.place holder Pervasives.JsxModules.place holder -Resolved opens 1 Stdlib -{"contents": {"kind": "markdown", "value": "```rescript\nint\n```"}} +null diff --git a/tests/analysis_tests/tests/src/expected/RecoveryOnProp.res.txt b/tests/analysis_tests/tests/src/expected/RecoveryOnProp.res.txt index 6533452eb5..2dc24193b4 100644 --- a/tests/analysis_tests/tests/src/expected/RecoveryOnProp.res.txt +++ b/tests/analysis_tests/tests/src/expected/RecoveryOnProp.res.txt @@ -21,6 +21,26 @@ Path Res "tags": [], "detail": "module Result", "documentation": null + }, { + "label": "RescriptReactErrorBoundary", + "kind": 9, + "tags": [], + "detail": "module RescriptReactErrorBoundary", + "documentation": null, + "data": { + "modulePath": "RescriptReactErrorBoundary", + "filePath": "src/RecoveryOnProp.res" + } + }, { + "label": "RescriptReactRouter", + "kind": 9, + "tags": [], + "detail": "module RescriptReactRouter", + "documentation": null, + "data": { + "modulePath": "RescriptReactRouter", + "filePath": "src/RecoveryOnProp.res" + } }, { "label": "RescriptTools", "kind": 9, diff --git a/tests/analysis_tests/tests/src/expected/TypeDefinition.res.txt b/tests/analysis_tests/tests/src/expected/TypeDefinition.res.txt index 46a968e8f3..61a1d85668 100644 --- a/tests/analysis_tests/tests/src/expected/TypeDefinition.res.txt +++ b/tests/analysis_tests/tests/src/expected/TypeDefinition.res.txt @@ -8,7 +8,7 @@ TypeDefinition src/TypeDefinition.res 8:4 {"uri": "TypeDefinition.res", "range": {"start": {"line": 2, "character": 0}, "end": {"line": 2, "character": 28}}} TypeDefinition src/TypeDefinition.res 13:4 -{"uri": "TypeDefinition.res", "range": {"start": {"line": 11, "character": 0}, "end": {"line": 11, "character": 26}}} +null TypeDefinition src/TypeDefinition.res 16:13 {"uri": "TypeDefinition.res", "range": {"start": {"line": 2, "character": 0}, "end": {"line": 2, "character": 28}}}