diff --git a/analysis/src/completion_back_end.ml b/analysis/src/completion_back_end.ml index 2ebd1804826..5290b691e78 100644 --- a/analysis/src/completion_back_end.ml +++ b/analysis/src/completion_back_end.ml @@ -1783,7 +1783,22 @@ let rec complete_typed_value ?(type_arg_context : type_arg_context option) ] | Tvariant {env; constructors; variant_decl; variant_name} -> if Debug.verbose () then print_endline "[complete_typed_value]--> Tvariant"; + (* An extension constructor is named by its module path, as in + [Sub.Flag]; the prefix may also be the start of its last part. *) + let matches_prefix name = + prefix = "" + || Utils.starts_with name prefix + || + match String.rindex_opt name '.' with + | Some i -> + Utils.starts_with + (String.sub name (i + 1) (String.length name - i - 1)) + prefix + | None -> false + in constructors + |> List.filter (fun (constructor : Constructor.t) -> + matches_prefix constructor.cname.txt) |> List.map (fun (constructor : Constructor.t) -> let num_args = match constructor.args with @@ -1800,7 +1815,6 @@ let rec complete_typed_value ?(type_arg_context : type_arg_context option) (Constructor (constructor, variant_decl |> Shared.decl_to_string variant_name)) ~env) - |> filter_items ~prefix | Tpolyvariant {env; constructors; type_expr} -> if Debug.verbose () then print_endline "[complete_typed_value]--> Tpolyvariant"; @@ -2091,8 +2105,8 @@ let rec complete_typed_value ?(type_arg_context : type_arg_context option) module String_set = Set.Make (String) -let rec process_completable ~state ~debug ~full ~scope ~env ~pos ~for_hover - completable = +let rec process_completable_in_scope ~state ~debug ~full ~scope ~env ~pos + ~for_hover completable = if debug then Printf.printf "Completable: %s\n" (Completable.to_string completable); let package = full.package in @@ -2398,7 +2412,8 @@ let rec process_completable ~state ~debug ~full ~scope ~env ~pos ~for_hover match (fallback, items) with | Some fallback, (None | Some []) -> fallback - |> process_completable ~state ~debug ~full ~scope ~env ~pos ~for_hover + |> process_completable_in_scope ~state ~debug ~full ~scope ~env ~pos + ~for_hover | _, Some items -> items | None, None -> [] in @@ -2569,15 +2584,23 @@ let rec process_completable ~state ~debug ~full ~scope ~env ~pos ~for_hover typ_expr |> Type_utils.extract_type ~env:c.env ~package ~state with | Some (Tvariant v, _) -> - with_exhaustive_item c - ~cases: - (v.constructors - |> List.map (fun (constructor : Constructor.t) -> - constructor.cname.txt - ^ - match constructor.args with - | Args [] -> "" - | _ -> "(_)")) + let cases = + v.constructors + |> List.map (fun (constructor : Constructor.t) -> + constructor.cname.txt + ^ + match constructor.args with + | Args [] -> "" + | _ -> "(_)") + in + (* An open type can be extended elsewhere, so only a catch-all + case makes the switch exhaustive. *) + let cases = + match v.variant_decl.type_kind with + | Type_open -> cases @ ["_"] + | _ -> cases + in + with_exhaustive_item c ~cases | Some (Tpolyvariant v, _) -> with_exhaustive_item c ~cases: @@ -2625,3 +2648,32 @@ let rec process_completable ~state ~debug ~full ~scope ~env ~pos ~for_hover ~env ~insert_text:"todo(\"${0:TODO}\")"; ] else [] + +(* The names of the modules around [pos] in [file], outermost first. *) +let module_path_at ~(full : full) ~pos = + let rec in_items (items : Module.item list) = + match + items + |> List.find_opt (fun (item : Module.item) -> + Loc.has_pos ~pos item.loc + && + match item.kind with + | Module _ -> true + | _ -> false) + with + | Some {name; kind = Module {type_}} -> name :: in_module type_ + | _ -> [] + and in_module (m : Module.t) = + match m with + | Structure {items} -> in_items items + | Constraint (implementation, _) -> in_module implementation + | Ident _ -> [] + in + in_items full.file.structure.items + +let process_completable ~state ~debug ~full ~scope ~env ~pos ~for_hover + completable = + Type_utils.with_completion_scope ~file:full.file + ~module_path:(module_path_at ~full ~pos) ~pos ~scope (fun () -> + process_completable_in_scope ~state ~debug ~full ~scope ~env ~pos + ~for_hover completable) diff --git a/analysis/src/completion_expressions.ml b/analysis/src/completion_expressions.ml index 5a69c4bc843..ff25e7c8b93 100644 --- a/analysis/src/completion_expressions.ml +++ b/analysis/src/completion_expressions.ml @@ -157,6 +157,7 @@ let rec traverse_expr (exp : Parsetree.expression) ~expr_path ~pos Completable.NVariantPayload { constructor_name = Longident.last txt; + constructor_path = Longident.flatten txt; item_num = 0; source_arity = 1; }; @@ -170,6 +171,7 @@ let rec traverse_expr (exp : Parsetree.expression) ~expr_path ~pos Completable.NVariantPayload { constructor_name = Longident.last txt; + constructor_path = Longident.flatten txt; item_num; source_arity = List.length args; }; @@ -180,6 +182,7 @@ let rec traverse_expr (exp : Parsetree.expression) ~expr_path ~pos Completable.NVariantPayload { constructor_name = Longident.last txt; + constructor_path = Longident.flatten txt; item_num = item_num + 1; source_arity = List.length args; }; diff --git a/analysis/src/completion_front_end.ml b/analysis/src/completion_front_end.ml index 8ad988f56b3..0d5df19aeae 100644 --- a/analysis/src/completion_front_end.ml +++ b/analysis/src/completion_front_end.ml @@ -504,6 +504,7 @@ let completion_with_parser1 ~debug ~offset ~pos_cursor ~kind_file item_num = index; source_arity = List.length patterns; constructor_name = Longident.last txt; + constructor_path = Longident.flatten txt; } :: pattern_path) ?context_path) @@ -744,6 +745,12 @@ let completion_with_parser1 ~debug ~offset ~pos_cursor ~kind_file | Pstr_open {popen_lid} -> scope := !scope |> Scope.add_open ~lid:popen_lid.txt | Pstr_primitive vd -> scope_value_description vd + | Pstr_typext {ptyext_constructors} -> + ptyext_constructors + |> List.iter (fun (ext : Parsetree.extension_constructor) -> + scope := + !scope + |> Scope.add_constructor ~name:ext.pext_name.txt ~loc:ext.pext_loc) | Pstr_value (rec_flag, bindings) -> if rec_flag = Recursive then bindings |> List.iter scope_value_binding; bindings |> List.iter (fun vb -> iterator.value_binding iterator vb); diff --git a/analysis/src/completion_patterns.ml b/analysis/src/completion_patterns.ml index a9f5d508f1c..28e0e980bf0 100644 --- a/analysis/src/completion_patterns.ml +++ b/analysis/src/completion_patterns.ml @@ -212,6 +212,7 @@ and traverse_pattern (pat : Parsetree.pattern) ~pattern_path ~loc_has_cursor Completable.NVariantPayload { constructor_name = Longident.last txt; + constructor_path = Longident.flatten txt; item_num = 0; source_arity = 1; }; @@ -226,6 +227,7 @@ and traverse_pattern (pat : Parsetree.pattern) ~pattern_path ~loc_has_cursor Completable.NVariantPayload { constructor_name = Longident.last txt; + constructor_path = Longident.flatten txt; item_num; source_arity = List.length patterns; }; @@ -236,6 +238,7 @@ and traverse_pattern (pat : Parsetree.pattern) ~pattern_path ~loc_has_cursor Completable.NVariantPayload { constructor_name = Longident.last txt; + constructor_path = Longident.flatten txt; item_num = item_num + 1; source_arity = List.length patterns; }; diff --git a/analysis/src/process_cmt.ml b/analysis/src/process_cmt.ml index 18d854a5244..ebbd4b6a010 100644 --- a/analysis/src/process_cmt.ml +++ b/analysis/src/process_cmt.ml @@ -35,6 +35,54 @@ let map_record_field {Types.ld_id; ld_type; ld_attributes; ld_optional} = deprecated = Process_attributes.find_deprecated_attribute ld_attributes; } +(* The constructors of [type t += ...] are registered as constructors of an + open type named [t], so that completion can offer them for values of + type [t]. They are not part of any type declaration, hence the stand-in + declaration that carries the kind and, as its manifest, the extended + type, which completion compares with the type it completes. *) +let add_extension_constructor ~(env : Env.t) ~id ~name + (ext : Types.extension_constructor) = + let type_decl : Types.type_declaration = + { + type_params = []; + type_arity = 0; + type_kind = Type_open; + type_private = Public; + type_manifest = Some (Ctype.newconstr ext.ext_type_path []); + type_variance = []; + type_newtype_level = None; + type_loc = Location.none; + type_attributes = []; + type_immediate = false; + type_representation = Boxed; + type_shape = Unstated; + type_inlined_types = []; + } + in + let stamp = Ident.binding_time id in + let item = + { + Constructor.stamp; + cname = name; + args = + (match ext.ext_args with + | Cstr_tuple args -> + Args (args |> List.map (fun t -> (t, Location.none))) + | Cstr_record fields -> + InlineRecord (fields |> List.map map_record_field)); + res = ext.ext_ret_type; + type_decl = (Path.last ext.ext_type_path, type_decl); + docstring = attrs_to_docstring ext.ext_attributes; + deprecated = + Process_attributes.find_deprecated_attribute ext.ext_attributes; + } + in + let declared = + Process_attributes.new_declared ~item ~extent:ext.ext_loc ~name ~stamp + ~module_path:env.module_path true ext.ext_attributes + in + Stamps.add_constructor env.stamps stamp declared + let rec for_type_signature_item ~(env : Shared_types.Env.t) ~(exported : Exported.t) (item : Types.signature_item) = match item with @@ -148,7 +196,7 @@ let rec for_type_signature_item ~(env : Shared_types.Env.t) let name = Ident.name ident in let declared = add_declared ~extent:md_loc - ~item:(for_type_module ~name ~env md_type) + ~item:(for_type_module ~name ~env:(env |> Env.add_module ~name) md_type) ~name:(Location.mkloc name md_loc) ~stamp:(Ident.binding_time ident) ~env md_attributes (Exported.add exported Exported.Module) @@ -165,6 +213,11 @@ let rec for_type_signature_item ~(env : Shared_types.Env.t) loc = declared.extent_loc; }; ] + | Sig_typext (id, ext, _) -> + add_extension_constructor ~env ~id + ~name:(Location.mkloc (Ident.name id) ext.ext_loc) + ext; + [] | _ -> [] and for_type_signature ~name ~env signature = @@ -328,6 +381,12 @@ let for_type_declaration ~env ~(exported : Exported.t) loc = declared.extent_loc; } +let add_extension_constructors ~(env : Env.t) {Typedtree.tyext_constructors} = + tyext_constructors + |> List.iter + (fun ({ext_id; ext_name; ext_type} : Typedtree.extension_constructor) -> + add_extension_constructor ~env ~id:ext_id ~name:ext_name ext_type) + let rec for_signature_item ~env ~(exported : Exported.t) (item : Typedtree.signature_item) = match item.sig_desc with @@ -401,6 +460,9 @@ let rec for_signature_item ~env ~(exported : Exported.t) incl_type [] in top_level + | Tsig_typext type_extension -> + add_extension_constructors ~env type_extension; + [] (* TODO: process other things here *) | _ -> [] @@ -645,6 +707,9 @@ let rec for_structure_item ~(env : Shared_types.Env.t) ~(exported : Exported.t) | _ -> Types.Trec_next in decl |> for_type_declaration ~env ~exported ~rec_status) + | Tstr_typext type_extension -> + add_extension_constructors ~env type_extension; + [] | _ -> [] and for_module ~env mod_desc module_name = diff --git a/analysis/src/shared_types.ml b/analysis/src/shared_types.ml index 5333f408325..802656983c4 100644 --- a/analysis/src/shared_types.ml +++ b/analysis/src/shared_types.ml @@ -378,6 +378,9 @@ and completion_type = | Tvariant of { env: Query_env.t; constructors: Constructor.t list; + extension_envs: (Constructor.t * Query_env.t) list; + (** The environments of the files declaring extension + constructors, where their payloads are typed *) variant_decl: Types.type_declaration; variant_name: string; } @@ -606,6 +609,8 @@ module Completable = struct | NRecordBody of {seen_fields: string list} | NVariantPayload of { constructor_name: string; + constructor_path: string list; + (** The constructor as written, with its module path *) item_num: int; source_arity: int; } diff --git a/analysis/src/type_utils.ml b/analysis/src/type_utils.ml index 0ad1ba84110..66e5de46702 100644 --- a/analysis/src/type_utils.ml +++ b/analysis/src/type_utils.ml @@ -361,6 +361,191 @@ let extract_function_type2 ?type_arg_context ~state ~env ~package typ = in loop ?type_arg_context ~env [] typ +(* The file being edited, the module path at the cursor and the scope there, + while a completion request runs. Extension constructors are named + relative to it: unlike ordinary constructors they can't be found from the + expected type, so they have to be written so that they are in scope + there. *) +let completion_scope : + (File.t * string list * Pos.t * Scope_types.item list) option ref = + ref None + +let with_completion_scope ~file ~module_path ~pos ~scope f = + let previous = !completion_scope in + completion_scope := Some (file, module_path, pos, scope); + Fun.protect ~finally:(fun () -> completion_scope := previous) f + +(* The constructor written [path] in a payload position, with the + environment its payload is typed in. An ordinary constructor is found by + its name. An extension constructor is named by its module path from the + cursor: written qualified, it is the one that path names; unqualified, it + is looked up in the scope at the cursor as the compiler does, the most + recent declaration or open bringing a constructor of that name and type + into scope. *) +let find_payload_constructor ~(env : Query_env.t) ~constructors ~extension_envs + path = + let with_env c = + (c, List.assq_opt c extension_envs |> Option.value ~default:env) + in + let rec ends_with l suffix = + l = suffix + || + match l with + | _ :: l -> ends_with l suffix + | [] -> false + in + let parts (c : Constructor.t) = String.split_on_char '.' c.cname.txt in + (* The constructors [path] names, possibly from an opened module, or + written from further out than the cursor. *) + let named path = + constructors + |> List.filter (fun c -> + ends_with (parts c) path || ends_with path (parts c)) + in + let exact path = constructors |> List.find_opt (fun c -> parts c = path) in + let last l = List.nth_opt l (List.length l - 1) in + let found = + match (extension_envs, path, !completion_scope) with + | [], _, _ -> + constructors + |> List.find_opt (fun (c : Constructor.t) -> Some c.cname.txt = last path) + | _, [name], Some ((file : File.t), _, _, scope) -> + let declared_at loc (c : Constructor.t) = + (snd (with_env c) : Query_env.t).file.uri = file.uri + && Loc.has_pos ~pos:(Loc.start c.cname.loc) loc + in + let rec lookup (scope : Scope_types.item list) = + match scope with + | [] -> exact path + | Constructor (n, loc) :: scope when n = name -> ( + match constructors |> List.find_opt (declared_at loc) with + | Some c -> Some c + | None -> lookup scope) + | Open opened :: scope -> ( + (* A raw open ends in a placeholder for the name it qualifies. *) + let opened = + List.filteri (fun i _ -> i < List.length opened - 1) opened + in + (* A constructor named without a module path is declared around + the cursor, so no open brings it into scope. *) + let in_module (c : Constructor.t) = List.length (parts c) > 1 in + match last (named (opened @ path) |> List.filter in_module) with + | Some c -> Some c + | None -> lookup scope) + | _ :: scope -> lookup scope + in + lookup scope + | _ -> ( + match exact path with + | Some c -> Some c + | None -> last (named path)) + in + found |> Option.map with_env + +(* The stamp under which [typ] is declared in [file]. *) +let type_stamp (file : File.t) (typ : Type.t) = + let found = ref None in + file.stamps + |> Stamps.iter_types (fun stamp (declared : Type.t Declared.t) -> + if declared.item == typ then found := Some stamp); + !found + +(* The constructors of an open type are those of its extensions, here the + ones in the type's file and in the current file. An extension names the + type it extends by its path where it is declared: an identifier of the + type's own file, or a path resolved from the extension's file. The + constructors are named by their module path, since an extension + constructor can't be found from the expected type alone, and come with + the environment of their file, where their payloads are typed. *) +let extension_constructors ~state ~package ~(current_file : File.t) + ~(type_file : File.t) ~type_stamp ~type_name ~decl = + let current_file, scope_path, cursor = + match !completion_scope with + | Some (file, module_path, pos, _) -> (file, module_path, Some pos) + | None -> (current_file, [], None) + in + (* An extension in a module type declares no constructor. *) + let rec in_module_type (path : Module_path.t) = + match path with + | ExportedModule {is_type = true} -> true + | ExportedModule {module_path} | IncludedModule (_, module_path) -> + in_module_type module_path + | File _ | NotVisible -> false + in + (* An extension of the edited file is in scope from its declaration on. *) + let declared_before_cursor (file : File.t) (declared : _ Declared.t) = + match cursor with + | Some pos when file.uri = current_file.uri -> + Loc.start declared.extent_loc <= pos + | _ -> true + in + let extends (file : File.t) (ext_decl : Types.type_declaration) = + match (type_stamp, ext_decl.type_manifest) with + | None, _ -> true + | Some stamp, Some {desc = Tconstr (Pident id, _, _)} -> + file.uri = type_file.uri && Ident.binding_time id = stamp + | Some stamp, Some {desc = Tconstr (path, _, _)} -> ( + match + References.dig_constructor ~state ~env:(Query_env.from_file file) + ~package path + with + | Some (env, declared) -> + env.file.uri = type_file.uri && declared.stamp = stamp + | None -> false) + | Some _, _ -> false + in + let found = Hashtbl.create 8 in + let files = + if current_file.uri = type_file.uri then [type_file] + else [type_file; current_file] + in + files + |> List.iter (fun (file : File.t) -> + file.stamps + |> Stamps.iter_constructors + (fun stamp (declared : Constructor.t Declared.t) -> + let name, ext_decl = declared.item.type_decl in + if + name = type_name + && ext_decl.type_kind = Type_open + && declared_before_cursor file declared + && (not (in_module_type declared.module_path)) + && extends file ext_decl + then Hashtbl.replace found (file.uri, stamp) (file, declared))); + Hashtbl.to_seq_values found + |> List.of_seq + |> List.sort + (fun + ((_, a) : File.t * Constructor.t Declared.t) + ((_, b) : File.t * Constructor.t Declared.t) + -> + compare + ( a.item.cname.loc.loc_start.pos_fname, + a.item.cname.loc.loc_start.pos_cnum ) + ( b.item.cname.loc.loc_start.pos_fname, + b.item.cname.loc.loc_start.pos_cnum )) + |> List.map (fun ((file : File.t), (declared : Constructor.t Declared.t)) -> + let path = + Module_path.to_path declared.module_path declared.item.cname.txt + in + (* Inside a module, its own name and those of the modules around it + are not in scope: drop the module path shared with the cursor. *) + let rec relative path scope = + match (path, scope) with + | p :: (_ :: _ as path), s :: scope when p = s -> relative path scope + | _ -> path + in + let path = + if file.uri = current_file.uri then relative path scope_path + else Utils.flatten_any_namespace_in_path (file.module_name :: path) + in + ( { + declared.item with + cname = {declared.item.cname with txt = String.concat "." path}; + type_decl = (type_name, decl); + }, + Query_env.from_file file )) + let rec extract_type ?(print_opening_debug = true) ?(type_arg_context : type_arg_context option) ?(type_arg_context_from_type_manifest : type_arg_context option) ~env ~state @@ -441,10 +626,35 @@ let rec extract_type ?(print_opening_debug = true) { env = env_from_item; constructors; + extension_envs = []; variant_name = name.txt; variant_decl = decl; }, type_arg_context ) + | Some (env_from_item, {name; stamp; item = {decl; kind = Type.Open}}) + when decl.type_manifest = None -> ( + let type_arg_context = + maybe_set_type_arg_ctx ~type_params:decl.type_params ~type_args env + in + match + extension_constructors ~state ~package ~current_file:env.file + ~type_file:env_from_item.file ~type_stamp:(Some stamp) + ~type_name:name.txt ~decl + with + | [] when name.txt = "t" -> + Some (TtypeT {env = env_from_item; path}, type_arg_context) + | [] -> None + | extension_envs -> + Some + ( Tvariant + { + env = env_from_item; + constructors = List.map fst extension_envs; + extension_envs; + variant_name = name.txt; + variant_decl = decl; + }, + type_arg_context )) | Some (env_from_declaration, {item = {kind = Record fields; decl}}) -> if Debug.verbose () then print_endline "[extract_type]--> found record"; (* Need to create a new type arg context here because we're sending along a type expr that might have type vars. *) @@ -600,7 +810,30 @@ let extract_type_from_resolved_type (typ : Type.t) ~env ~full ~state = | Variant constructors -> Some (Tvariant - {env; constructors; variant_name = typ.name; variant_decl = typ.decl}) + { + env; + constructors; + extension_envs = []; + variant_name = typ.name; + variant_decl = typ.decl; + }) + | Open when typ.decl.type_manifest = None -> ( + match + extension_constructors ~state ~package:full.package + ~current_file:full.file ~type_file:env.file + ~type_stamp:(type_stamp env.file typ) ~type_name:typ.name ~decl:typ.decl + with + | [] -> None + | extension_envs -> + Some + (Tvariant + { + env; + constructors = List.map fst extension_envs; + extension_envs; + variant_name = typ.name; + variant_decl = typ.decl; + })) | Abstract _ | Open -> ( match typ.decl.type_manifest with | None -> None @@ -760,19 +993,19 @@ let rec resolve_nested ?type_arg_context ~env ~full ~state ~nested ?ctx |> extract_type ~env ~state ~package:full.package |> Utils.Option.flat_map (fun (t, type_arg_context) -> t |> resolve_nested ?type_arg_context ~env ~state ~full ~nested) - | ( NVariantPayload {constructor_name; item_num; source_arity}, - Tvariant {env; constructors} ) -> ( + | ( NVariantPayload + {constructor_name; constructor_path; item_num; source_arity}, + Tvariant {env; constructors; extension_envs} ) -> ( if Debug.verbose () then Printf.printf "[nested]--> trying to move into variant payload $%i of constructor \ '%s'\n" item_num constructor_name; match - constructors - |> List.find_opt (fun (c : Constructor.t) -> - c.cname.txt = constructor_name) + find_payload_constructor ~env ~constructors ~extension_envs + constructor_path with - | Some {args = Args args} -> ( + | Some ({args = Args args}, env) -> ( if Debug.verbose () then print_endline "[nested]--> found constructor (Args type)"; let item_num, nested = @@ -799,7 +1032,7 @@ let rec resolve_nested ?type_arg_context ~env ~full ~state ~nested ?ctx (List.length nested); typ |> resolve_nested ?type_arg_context ~env ~state ~full ~nested) ) - | Some {args = InlineRecord fields} when item_num = 0 -> + | Some ({args = InlineRecord fields}, env) when item_num = 0 -> if Debug.verbose () then print_endline "[nested]--> found constructor (inline record)"; TinlineRecord {env; fields} @@ -901,14 +1134,13 @@ let rec resolve_nested_pattern_path (typ : inner_type) ~env ~full ~state ~nested | None -> None | Some typ -> TypeExpr typ |> resolve_nested_pattern_path ~env ~state ~full ~nested) - | ( NVariantPayload {constructor_name; item_num; source_arity}, - Tvariant {env; constructors} ) -> ( + | ( NVariantPayload {constructor_path; item_num; source_arity}, + Tvariant {env; constructors; extension_envs} ) -> ( match - constructors - |> List.find_opt (fun (constructor : Constructor.t) -> - constructor.cname.txt = constructor_name) + find_payload_constructor ~env ~constructors ~extension_envs + constructor_path with - | Some {args = Args args} -> ( + | Some ({args = Args args}, env) -> ( let item_num, nested = normalize_constructor_payload_path ~argument_count:(List.length args) ~source_arity ~item_num ~nested @@ -918,10 +1150,10 @@ let rec resolve_nested_pattern_path (typ : inner_type) ~env ~full ~state ~nested TypeExpr typ |> resolve_nested_pattern_path ~env ~state ~full ~nested | None -> None) - | Some {args = InlineRecord fields} when item_num = 0 -> + | Some ({args = InlineRecord fields}, env) when item_num = 0 -> ExtractedType (TinlineRecord {env; fields}) |> resolve_nested_pattern_path ~env ~state ~full ~nested - | Some {args = InlineRecord _} | None -> None) + | Some ({args = InlineRecord _}, _) | None -> None) | ( NPolyvariantPayload {constructor_name; item_num; source_arity}, Tpolyvariant {env; constructors} ) -> ( match @@ -1061,15 +1293,23 @@ module Codegen = struct = match extracted_type with | Tvariant v -> + (* Other files can extend an open type, so only a catch-all case + makes the switch exhaustive. *) + let catch_all = + match v.variant_decl.type_kind with + | Type_open -> [any ()] + | Type_abstract | Type_record _ | Type_variant _ -> [] + in Some - (v.constructors - |> List.map (fun (c : Shared_types.Constructor.t) -> - mk_construct_pat - ?payload: - (match c.args with - | Args [] -> None - | _ -> Some (any ())) - c.cname.txt)) + ((v.constructors + |> List.map (fun (c : Shared_types.Constructor.t) -> + mk_construct_pat + ?payload: + (match c.args with + | Args [] -> None + | _ -> Some (any ())) + c.cname.txt)) + @ catch_all) | Tpolyvariant v -> Some (v.constructors diff --git a/analysis/src/xform.ml b/analysis/src/xform.ml index 394f7e9e1f7..e4cacd86978 100644 --- a/analysis/src/xform.ml +++ b/analysis/src/xform.ml @@ -406,6 +406,13 @@ module Expand_catch_all_for_variants = struct in {Ast_iterator.default_iterator with expr} + (* Other files can extend an open type, so its expansion keeps a + catch-all alternative after the constructors known here. *) + let open_type_catch_all (decl : Types.type_declaration) = + match decl.type_kind with + | Type_open -> ["_"] + | Type_abstract | Type_record _ | Type_variant _ -> [] + let xform ~state ~source ~kind_file ~path ~pos ~full ~structure ~code_actions ~debug = let result = ref None in @@ -445,7 +452,7 @@ module Expand_catch_all_for_variants = struct |> extract_type_from_expr ~state ~debug ~source ~kind_file ~full ~pos:(Pos.of_lexing switch_expr.pexp_loc.loc_end) with - | Some (Tvariant {constructors}) -> + | Some (Tvariant {constructors; variant_decl}) -> let missing_constructors = constructors |> List.filter (fun (c : Shared_types.Constructor.t) -> @@ -453,13 +460,14 @@ module Expand_catch_all_for_variants = struct in if List.length missing_constructors > 0 then let new_text = - missing_constructors + (missing_constructors |> List.map (fun (c : Shared_types.Constructor.t) -> c.cname.txt ^ match c.args with | Args [] -> "" - | Args _ | InlineRecord _ -> "(_)") + | Args _ | InlineRecord _ -> "(_)")) + @ open_type_catch_all variant_decl |> String.concat " | " in let range = Loc.range_of_loc catch_all_case.pc_lhs.ppat_loc in @@ -549,9 +557,13 @@ module Expand_catch_all_for_variants = struct if List.length missing_constructors > 0 || not has_none_case then let new_text = "Some(" - ^ (missing_constructors - |> List.map (fun (name, has_args) -> - name ^ if has_args then "(_)" else "") + ^ (((missing_constructors + |> List.map (fun (name, has_args) -> + name ^ if has_args then "(_)" else "")) + @ + match variant with + | Tvariant {variant_decl} -> open_type_catch_all variant_decl + | _ -> []) |> String.concat " | ") ^ ")" in diff --git a/changes/extensible-variant-completion.fix.md b/changes/extensible-variant-completion.fix.md new file mode 100644 index 00000000000..cf6be350475 --- /dev/null +++ b/changes/extensible-variant-completion.fix.md @@ -0,0 +1 @@ +- Editor completion offers the constructors of an extensible variant declared in the current file or in the type's file, and the exhaustive switch snippet for one ends with a `_` case. diff --git a/tests/analysis_tests/tests-namespaced-references/src/ExtensibleBase.res b/tests/analysis_tests/tests-namespaced-references/src/ExtensibleBase.res new file mode 100644 index 00000000000..cc1cf75a2b1 --- /dev/null +++ b/tests/analysis_tests/tests-namespaced-references/src/ExtensibleBase.res @@ -0,0 +1,4 @@ +type attr = .. +type attr += Flag | Size(int) + +let value: attr = Flag diff --git a/tests/analysis_tests/tests-namespaced-references/src/ExtensibleUse.res b/tests/analysis_tests/tests-namespaced-references/src/ExtensibleUse.res new file mode 100644 index 00000000000..3b818c5ed0b --- /dev/null +++ b/tests/analysis_tests/tests-namespaced-references/src/ExtensibleUse.res @@ -0,0 +1,4 @@ +let imported = ExtensibleBase.value + +// switch importe +// ^com diff --git a/tests/analysis_tests/tests-namespaced-references/src/expected/ExtensibleBase.res.txt b/tests/analysis_tests/tests-namespaced-references/src/expected/ExtensibleBase.res.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/analysis_tests/tests-namespaced-references/src/expected/ExtensibleUse.res.txt b/tests/analysis_tests/tests-namespaced-references/src/expected/ExtensibleUse.res.txt new file mode 100644 index 00000000000..a22af674ea9 --- /dev/null +++ b/tests/analysis_tests/tests-namespaced-references/src/expected/ExtensibleUse.res.txt @@ -0,0 +1,24 @@ +Complete src/ExtensibleUse.res 2:17 +XXX Not found! +Completable: CexhaustiveSwitch Value[importe] +Package opens Stdlib.place holder Pervasives.JsxModules.place holder MyNamespace.place holder +Resolved opens 2 MyNamespace Stdlib +ContextPath Value[importe] +Path importe +[ + { + "detail": "MyNamespace.ExtensibleBase.attr", + "kind": 12, + "label": "imported", + "tags": [] + }, + { + "detail": "insert exhaustive switch for value", + "filterText": "imported", + "insertText": "imported {\n | MyNamespace.ExtensibleBase.Flag => ${1:%todo}\n | MyNamespace.ExtensibleBase.Size(_) => ${2:%todo}\n | _ => ${3:%todo}\n }", + "insertTextFormat": 2, + "kind": 15, + "label": "imported (exhaustive switch)", + "tags": [] + } +] diff --git a/tests/analysis_tests/tests/src/CompletionExtensibleIface.res b/tests/analysis_tests/tests/src/CompletionExtensibleIface.res new file mode 100644 index 00000000000..e472b52a67c --- /dev/null +++ b/tests/analysis_tests/tests/src/CompletionExtensibleIface.res @@ -0,0 +1,14 @@ +type attr = .. +type attr += Top + +module Sub = { + type attr += Flag +} + +module Outer = { + module Inner = { + type attr += Deep + } +} + +let value: attr = Top diff --git a/tests/analysis_tests/tests/src/CompletionExtensibleIface.resi b/tests/analysis_tests/tests/src/CompletionExtensibleIface.resi new file mode 100644 index 00000000000..bb96a61c07b --- /dev/null +++ b/tests/analysis_tests/tests/src/CompletionExtensibleIface.resi @@ -0,0 +1,14 @@ +type attr = .. +type attr += Top + +module Sub: { + type attr += Flag +} + +module Outer: { + module Inner: { + type attr += Deep + } +} + +let value: attr diff --git a/tests/analysis_tests/tests/src/CompletionExtensibleIfaceUse.res b/tests/analysis_tests/tests/src/CompletionExtensibleIfaceUse.res new file mode 100644 index 00000000000..32f64d6f926 --- /dev/null +++ b/tests/analysis_tests/tests/src/CompletionExtensibleIfaceUse.res @@ -0,0 +1,4 @@ +let imported = CompletionExtensibleIface.value + +// switch importe +// ^com diff --git a/tests/analysis_tests/tests/src/CompletionExtensiblePayload.res b/tests/analysis_tests/tests/src/CompletionExtensiblePayload.res new file mode 100644 index 00000000000..c2a10331602 --- /dev/null +++ b/tests/analysis_tests/tests/src/CompletionExtensiblePayload.res @@ -0,0 +1,131 @@ +// Payloads of extensions are typed where the extension is declared +type color = Red | Blue +type record = {c: color} +type CompletionExtensiblePayloadBase.attr += + | Color(color) + | Boxed({b: color}) + | Wrapped(record) + | Pair(color, CompletionExtensiblePayloadBase.shape) + | Sized(CompletionExtensiblePayloadThird.size) + +let v: CompletionExtensiblePayloadBase.attr = Color(Red) +type attr = CompletionExtensiblePayloadBase.attr + +// let x: attr = Color() +// ^com + +// switch v { | Color() } +// ^com + +// let x: attr = Boxed({b: }) +// ^com + +// switch v { | Wrapped({c: }) } +// ^com + +// let x: attr = Pair(Red, ) +// ^com + +// switch v { | Pair(Red, ) } +// ^com + +// let x: attr = Sized() +// ^com + +// switch v { | Sized() } +// ^com + +// let x: attr = CompletionExtensiblePayloadBase.Shaped() +// ^com + +// Same-named constructors are told apart by their module path +module A = { + type CompletionExtensiblePayloadBase.attr += Value(bool) +} +module B = { + type CompletionExtensiblePayloadBase.attr += Value(option) + // let x: attr = Value() + // ^com +} + +// Payload types local to a nested module +module M = { + type local = X | Y + type CompletionExtensiblePayloadBase.attr += InM(local) +} + +// let x: attr = M.InM() +// ^com + +// switch v { | M.InM() } +// ^com + +// let x: attr = A.Value() +// ^com + +// let x: attr = B.Value() +// ^com + +// let x: attr = B.Value(Some()) +// ^com + +// switch v { | A.Value() } +// ^com + +// switch v { | B.Value() } +// ^com + +// let x: attr = CompletionExtensiblePayloadBase.Value() +// ^com + +// let x: attr = CompletionExtensiblePayload.B.Value() +// ^com + +// switch v { | CompletionExtensiblePayloadBase.Value() } +// ^com + +// Unqualified, the constructor of the most recent open is meant +open A + +// let x: attr = Value() +// ^com + +// switch v { | Value() } +// ^com + +open B + +// let x: attr = Value() +// ^com + +// switch v { | Value() } +// ^com + +// A local declaration after an open shadows the opened constructor +type CompletionExtensiblePayloadBase.attr += Value(CompletionExtensiblePayloadThird.size) + +// let x: attr = Value() +// ^com + +// switch v { | Value() } +// ^com + +// An extension in a module type declares no constructor +module type S = { + type CompletionExtensiblePayloadBase.attr += Phantom +} + +// let x: attr = P +// ^com + +// switch v +// ^com + +// An open after a local declaration shadows it in turn +open A + +// let x: attr = Value() +// ^com + +// switch v { | Value() } +// ^com diff --git a/tests/analysis_tests/tests/src/CompletionExtensiblePayloadBase.res b/tests/analysis_tests/tests/src/CompletionExtensiblePayloadBase.res new file mode 100644 index 00000000000..6eb9e7f50ae --- /dev/null +++ b/tests/analysis_tests/tests/src/CompletionExtensiblePayloadBase.res @@ -0,0 +1,3 @@ +type attr = .. +type shape = Circle | Square +type attr += Value(shape) | Shaped(shape) diff --git a/tests/analysis_tests/tests/src/CompletionExtensiblePayloadIface.res b/tests/analysis_tests/tests/src/CompletionExtensiblePayloadIface.res new file mode 100644 index 00000000000..ab1549deca7 --- /dev/null +++ b/tests/analysis_tests/tests/src/CompletionExtensiblePayloadIface.res @@ -0,0 +1,5 @@ +type attr = .. +type tone = Light | Dark +module Inner = { + type attr += Toned(tone) +} diff --git a/tests/analysis_tests/tests/src/CompletionExtensiblePayloadIface.resi b/tests/analysis_tests/tests/src/CompletionExtensiblePayloadIface.resi new file mode 100644 index 00000000000..e730cbab5f8 --- /dev/null +++ b/tests/analysis_tests/tests/src/CompletionExtensiblePayloadIface.resi @@ -0,0 +1,5 @@ +type attr = .. +type tone = Light | Dark +module Inner: { + type attr += Toned(tone) +} diff --git a/tests/analysis_tests/tests/src/CompletionExtensiblePayloadIfaceUse.res b/tests/analysis_tests/tests/src/CompletionExtensiblePayloadIfaceUse.res new file mode 100644 index 00000000000..793b1c5f73b --- /dev/null +++ b/tests/analysis_tests/tests/src/CompletionExtensiblePayloadIfaceUse.res @@ -0,0 +1,3 @@ +// let x: CompletionExtensiblePayloadIface.attr = CompletionExtensiblePayloadIface.Inner.Toned() +// ^com + diff --git a/tests/analysis_tests/tests/src/CompletionExtensiblePayloadThird.res b/tests/analysis_tests/tests/src/CompletionExtensiblePayloadThird.res new file mode 100644 index 00000000000..63a5cab1c87 --- /dev/null +++ b/tests/analysis_tests/tests/src/CompletionExtensiblePayloadThird.res @@ -0,0 +1 @@ +type size = Small | Large diff --git a/tests/analysis_tests/tests/src/CompletionExtensibleVariant.res b/tests/analysis_tests/tests/src/CompletionExtensibleVariant.res new file mode 100644 index 00000000000..3c313c2c151 --- /dev/null +++ b/tests/analysis_tests/tests/src/CompletionExtensibleVariant.res @@ -0,0 +1,71 @@ +type attr = .. +type attr += Str(string) | Num(int) + +module Sub = { + type attr += Flag | Toggle(bool) + // Inside the declaring module the constructor is not qualified + // let inside: attr = Fl + // ^com +} + +// let a: attr = Nu +// ^com + +let value: attr = Str("s") +// ^hov + +// switch value { | S +// ^com + +// switch valu +// ^com + +// Open types of the same name are told apart +module A = { + type t = .. + type t += FromA +} +module B = { + type t = .. + type t += FromB +} +type A.t += MoreA + +let a: A.t = A.FromA + +// switch a { | M +// ^com + +// switch a { | F +// ^com + +// switch value { | Fl +// ^com + +// An extension declared later is not in scope yet +// switch value { | La +// ^com + +type attr += Later + +// Payload of a qualified extension constructor +// let toggled: attr = Sub.Toggle(t +// ^com + +// Expanding the catch-all of an open type +let _x = switch value { +| Str(_) => "str" +| _ => "other" +// ^xfm +} + +let optValue = Some(value) +let _y = switch optValue { +| Some(Str(_)) => "str" +| _ => "other" +// ^xfm +} + +// An exhaustive switch of an open type +// value +// ^xfm^ diff --git a/tests/analysis_tests/tests/src/CompletionExtensibleVariantUse.res b/tests/analysis_tests/tests/src/CompletionExtensibleVariantUse.res new file mode 100644 index 00000000000..e4c99cf2214 --- /dev/null +++ b/tests/analysis_tests/tests/src/CompletionExtensibleVariantUse.res @@ -0,0 +1,6 @@ +type CompletionExtensibleVariant.attr += Local + +let imported = CompletionExtensibleVariant.value + +// switch importe +// ^com diff --git a/tests/analysis_tests/tests/src/expected/CompletionExtensibleIface.res.txt b/tests/analysis_tests/tests/src/expected/CompletionExtensibleIface.res.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/analysis_tests/tests/src/expected/CompletionExtensibleIface.resi.txt b/tests/analysis_tests/tests/src/expected/CompletionExtensibleIface.resi.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/analysis_tests/tests/src/expected/CompletionExtensibleIfaceUse.res.txt b/tests/analysis_tests/tests/src/expected/CompletionExtensibleIfaceUse.res.txt new file mode 100644 index 00000000000..62f46909364 --- /dev/null +++ b/tests/analysis_tests/tests/src/expected/CompletionExtensibleIfaceUse.res.txt @@ -0,0 +1,25 @@ +Complete src/CompletionExtensibleIfaceUse.res 2:17 +XXX Not found! +Completable: CexhaustiveSwitch Value[importe] +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[importe] +Path importe +[ + { + "detail": "CompletionExtensibleIface.attr", + "kind": 12, + "label": "imported", + "tags": [] + }, + { + "detail": "insert exhaustive switch for value", + "filterText": "imported", + "insertText": "imported {\n | CompletionExtensibleIface.Top => ${1:%todo}\n | CompletionExtensibleIface.Sub.Flag => ${2:%todo}\n | CompletionExtensibleIface.Outer.Inner.Deep => ${3:%todo}\n | _ => ${4:%todo}\n }", + "insertTextFormat": 2, + "kind": 15, + "label": "imported (exhaustive switch)", + "tags": [] + } +] + diff --git a/tests/analysis_tests/tests/src/expected/CompletionExtensiblePayload.res.txt b/tests/analysis_tests/tests/src/expected/CompletionExtensiblePayload.res.txt new file mode 100644 index 00000000000..7308c6031b9 --- /dev/null +++ b/tests/analysis_tests/tests/src/expected/CompletionExtensiblePayload.res.txt @@ -0,0 +1,1285 @@ +Complete src/CompletionExtensiblePayload.res 13:23 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Color($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { + "detail": "Red", + "documentation": { + "kind": "markdown", + "value": "```rescript\nRed\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Red", + "insertTextFormat": 2, + "kind": 4, + "label": "Red", + "tags": [] + }, + { + "detail": "Blue", + "documentation": { + "kind": "markdown", + "value": "```rescript\nBlue\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Blue", + "insertTextFormat": 2, + "kind": 4, + "label": "Blue", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 16:22 +pos_cursor:[16:22] pos_no_white:[16:21] Found pattern:[16:16->16:23] +Ppat_construct Color:[16:16->16:21] +pos_cursor:[16:22] pos_no_white:[16:21] Found pattern:[16:21->16:23] +Ppat_construct ():[16:21->16:23] +Completable: Cpattern Value[v]->variantPayload::Color($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[v] +Path v +[ + { + "detail": "Red", + "documentation": { + "kind": "markdown", + "value": "```rescript\nRed\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Red", + "insertTextFormat": 2, + "kind": 4, + "label": "Red", + "tags": [] + }, + { + "detail": "Blue", + "documentation": { + "kind": "markdown", + "value": "```rescript\nBlue\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Blue", + "insertTextFormat": 2, + "kind": 4, + "label": "Blue", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 19:27 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Boxed($0), recordField(b) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { + "detail": "Red", + "documentation": { + "kind": "markdown", + "value": "```rescript\nRed\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Red", + "insertTextFormat": 2, + "kind": 4, + "label": "Red", + "tags": [] + }, + { + "detail": "Blue", + "documentation": { + "kind": "markdown", + "value": "```rescript\nBlue\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Blue", + "insertTextFormat": 2, + "kind": 4, + "label": "Blue", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 22:28 +pos_cursor:[22:28] pos_no_white:[22:26] Found pattern:[22:16->22:30] +Ppat_construct Wrapped:[22:16->22:23] +pos_cursor:[22:28] pos_no_white:[22:26] Found pattern:[22:24->22:29] +Completable: Cpattern Value[v]->variantPayload::Wrapped($0), recordField(c) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[v] +Path v +[ + { + "detail": "Red", + "documentation": { + "kind": "markdown", + "value": "```rescript\nRed\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Red", + "insertTextFormat": 2, + "kind": 4, + "label": "Red", + "tags": [] + }, + { + "detail": "Blue", + "documentation": { + "kind": "markdown", + "value": "```rescript\nBlue\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Blue", + "insertTextFormat": 2, + "kind": 4, + "label": "Blue", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 25:27 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Pair($1) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { + "detail": "Circle", + "documentation": { + "kind": "markdown", + "value": "```rescript\nCircle\n```\n\n```rescript\ntype shape = Circle | Square\n```" + }, + "insertText": "Circle", + "insertTextFormat": 2, + "kind": 4, + "label": "Circle", + "tags": [] + }, + { + "detail": "Square", + "documentation": { + "kind": "markdown", + "value": "```rescript\nSquare\n```\n\n```rescript\ntype shape = Circle | Square\n```" + }, + "insertText": "Square", + "insertTextFormat": 2, + "kind": 4, + "label": "Square", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 28:26 +pos_cursor:[28:26] pos_no_white:[28:24] Found pattern:[28:16->28:27] +Ppat_construct Pair:[28:16->28:20] +Completable: Cpattern Value[v]->variantPayload::Pair($1) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[v] +Path v +[ + { + "detail": "Circle", + "documentation": { + "kind": "markdown", + "value": "```rescript\nCircle\n```\n\n```rescript\ntype shape = Circle | Square\n```" + }, + "insertText": "Circle", + "insertTextFormat": 2, + "kind": 4, + "label": "Circle", + "tags": [] + }, + { + "detail": "Square", + "documentation": { + "kind": "markdown", + "value": "```rescript\nSquare\n```\n\n```rescript\ntype shape = Circle | Square\n```" + }, + "insertText": "Square", + "insertTextFormat": 2, + "kind": 4, + "label": "Square", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 31:23 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Sized($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { + "detail": "Small", + "documentation": { + "kind": "markdown", + "value": "```rescript\nSmall\n```\n\n```rescript\ntype size = Small | Large\n```" + }, + "insertText": "Small", + "insertTextFormat": 2, + "kind": 4, + "label": "Small", + "tags": [] + }, + { + "detail": "Large", + "documentation": { + "kind": "markdown", + "value": "```rescript\nLarge\n```\n\n```rescript\ntype size = Small | Large\n```" + }, + "insertText": "Large", + "insertTextFormat": 2, + "kind": 4, + "label": "Large", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 34:22 +pos_cursor:[34:22] pos_no_white:[34:21] Found pattern:[34:16->34:23] +Ppat_construct Sized:[34:16->34:21] +pos_cursor:[34:22] pos_no_white:[34:21] Found pattern:[34:21->34:23] +Ppat_construct ():[34:21->34:23] +Completable: Cpattern Value[v]->variantPayload::Sized($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[v] +Path v +[ + { + "detail": "Small", + "documentation": { + "kind": "markdown", + "value": "```rescript\nSmall\n```\n\n```rescript\ntype size = Small | Large\n```" + }, + "insertText": "Small", + "insertTextFormat": 2, + "kind": 4, + "label": "Small", + "tags": [] + }, + { + "detail": "Large", + "documentation": { + "kind": "markdown", + "value": "```rescript\nLarge\n```\n\n```rescript\ntype size = Small | Large\n```" + }, + "insertText": "Large", + "insertTextFormat": 2, + "kind": 4, + "label": "Large", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 37:56 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Shaped($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { + "detail": "Circle", + "documentation": { + "kind": "markdown", + "value": "```rescript\nCircle\n```\n\n```rescript\ntype shape = Circle | Square\n```" + }, + "insertText": "Circle", + "insertTextFormat": 2, + "kind": 4, + "label": "Circle", + "tags": [] + }, + { + "detail": "Square", + "documentation": { + "kind": "markdown", + "value": "```rescript\nSquare\n```\n\n```rescript\ntype shape = Circle | Square\n```" + }, + "insertText": "Square", + "insertTextFormat": 2, + "kind": 4, + "label": "Square", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 46:25 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Value($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { + "detail": "color", + "documentation": { + "kind": "markdown", + "value": "```rescript\ntype color = Red | Blue\n```" + }, + "kind": 12, + "label": "None", + "tags": [] + }, + { + "detail": "color", + "documentation": { + "kind": "markdown", + "value": "```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some($0)", + "insertTextFormat": 2, + "kind": 12, + "label": "Some(_)", + "tags": [] + }, + { + "detail": "Red", + "documentation": { + "kind": "markdown", + "value": "```rescript\nRed\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some(Red)", + "insertTextFormat": 2, + "kind": 4, + "label": "Some(Red)", + "tags": [] + }, + { + "detail": "Blue", + "documentation": { + "kind": "markdown", + "value": "```rescript\nBlue\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some(Blue)", + "insertTextFormat": 2, + "kind": 4, + "label": "Some(Blue)", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 56:23 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::InM($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { + "detail": "X", + "documentation": { + "kind": "markdown", + "value": "```rescript\nX\n```\n\n```rescript\ntype local = X | Y\n```" + }, + "insertText": "X", + "insertTextFormat": 2, + "kind": 4, + "label": "X", + "tags": [] + }, + { + "detail": "Y", + "documentation": { + "kind": "markdown", + "value": "```rescript\nY\n```\n\n```rescript\ntype local = X | Y\n```" + }, + "insertText": "Y", + "insertTextFormat": 2, + "kind": 4, + "label": "Y", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 59:22 +pos_cursor:[59:22] pos_no_white:[59:21] Found pattern:[59:16->59:23] +Ppat_construct M.InM:[59:16->59:21] +pos_cursor:[59:22] pos_no_white:[59:21] Found pattern:[59:21->59:23] +Ppat_construct ():[59:21->59:23] +Completable: Cpattern Value[v]->variantPayload::InM($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[v] +Path v +[ + { + "detail": "X", + "documentation": { + "kind": "markdown", + "value": "```rescript\nX\n```\n\n```rescript\ntype local = X | Y\n```" + }, + "insertText": "X", + "insertTextFormat": 2, + "kind": 4, + "label": "X", + "tags": [] + }, + { + "detail": "Y", + "documentation": { + "kind": "markdown", + "value": "```rescript\nY\n```\n\n```rescript\ntype local = X | Y\n```" + }, + "insertText": "Y", + "insertTextFormat": 2, + "kind": 4, + "label": "Y", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 62:25 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Value($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { "detail": "bool", "kind": 4, "label": "true", "tags": [] }, + { "detail": "bool", "kind": 4, "label": "false", "tags": [] } +] + +Complete src/CompletionExtensiblePayload.res 65:25 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Value($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { + "detail": "color", + "documentation": { + "kind": "markdown", + "value": "```rescript\ntype color = Red | Blue\n```" + }, + "kind": 12, + "label": "None", + "tags": [] + }, + { + "detail": "color", + "documentation": { + "kind": "markdown", + "value": "```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some($0)", + "insertTextFormat": 2, + "kind": 12, + "label": "Some(_)", + "tags": [] + }, + { + "detail": "Red", + "documentation": { + "kind": "markdown", + "value": "```rescript\nRed\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some(Red)", + "insertTextFormat": 2, + "kind": 4, + "label": "Some(Red)", + "tags": [] + }, + { + "detail": "Blue", + "documentation": { + "kind": "markdown", + "value": "```rescript\nBlue\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some(Blue)", + "insertTextFormat": 2, + "kind": 4, + "label": "Some(Blue)", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 68:30 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Value($0), variantPayload::Some($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { + "detail": "Red", + "documentation": { + "kind": "markdown", + "value": "```rescript\nRed\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Red", + "insertTextFormat": 2, + "kind": 4, + "label": "Red", + "tags": [] + }, + { + "detail": "Blue", + "documentation": { + "kind": "markdown", + "value": "```rescript\nBlue\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Blue", + "insertTextFormat": 2, + "kind": 4, + "label": "Blue", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 71:24 +pos_cursor:[71:24] pos_no_white:[71:23] Found pattern:[71:16->71:25] +Ppat_construct A.Value:[71:16->71:23] +pos_cursor:[71:24] pos_no_white:[71:23] Found pattern:[71:23->71:25] +Ppat_construct ():[71:23->71:25] +Completable: Cpattern Value[v]->variantPayload::Value($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[v] +Path v +[ + { "detail": "bool", "kind": 4, "label": "true", "tags": [] }, + { "detail": "bool", "kind": 4, "label": "false", "tags": [] } +] + +Complete src/CompletionExtensiblePayload.res 74:24 +pos_cursor:[74:24] pos_no_white:[74:23] Found pattern:[74:16->74:25] +Ppat_construct B.Value:[74:16->74:23] +pos_cursor:[74:24] pos_no_white:[74:23] Found pattern:[74:23->74:25] +Ppat_construct ():[74:23->74:25] +Completable: Cpattern Value[v]->variantPayload::Value($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[v] +Path v +[ + { + "detail": "color", + "documentation": { + "kind": "markdown", + "value": "```rescript\ntype color = Red | Blue\n```" + }, + "kind": 12, + "label": "None", + "tags": [] + }, + { + "detail": "color", + "documentation": { + "kind": "markdown", + "value": "```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some(${1:_})", + "insertTextFormat": 2, + "kind": 12, + "label": "Some(_)", + "tags": [] + }, + { + "detail": "Red", + "documentation": { + "kind": "markdown", + "value": "```rescript\nRed\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some(Red)", + "insertTextFormat": 2, + "kind": 4, + "label": "Some(Red)", + "tags": [] + }, + { + "detail": "Blue", + "documentation": { + "kind": "markdown", + "value": "```rescript\nBlue\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some(Blue)", + "insertTextFormat": 2, + "kind": 4, + "label": "Some(Blue)", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 77:55 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Value($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { + "detail": "Circle", + "documentation": { + "kind": "markdown", + "value": "```rescript\nCircle\n```\n\n```rescript\ntype shape = Circle | Square\n```" + }, + "insertText": "Circle", + "insertTextFormat": 2, + "kind": 4, + "label": "Circle", + "tags": [] + }, + { + "detail": "Square", + "documentation": { + "kind": "markdown", + "value": "```rescript\nSquare\n```\n\n```rescript\ntype shape = Circle | Square\n```" + }, + "insertText": "Square", + "insertTextFormat": 2, + "kind": 4, + "label": "Square", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 80:53 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Value($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { + "detail": "color", + "documentation": { + "kind": "markdown", + "value": "```rescript\ntype color = Red | Blue\n```" + }, + "kind": 12, + "label": "None", + "tags": [] + }, + { + "detail": "color", + "documentation": { + "kind": "markdown", + "value": "```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some($0)", + "insertTextFormat": 2, + "kind": 12, + "label": "Some(_)", + "tags": [] + }, + { + "detail": "Red", + "documentation": { + "kind": "markdown", + "value": "```rescript\nRed\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some(Red)", + "insertTextFormat": 2, + "kind": 4, + "label": "Some(Red)", + "tags": [] + }, + { + "detail": "Blue", + "documentation": { + "kind": "markdown", + "value": "```rescript\nBlue\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some(Blue)", + "insertTextFormat": 2, + "kind": 4, + "label": "Some(Blue)", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 83:54 +pos_cursor:[83:54] pos_no_white:[83:53] Found pattern:[83:16->83:55] +Ppat_construct CompletionExtensiblePayloadBase.Value:[83:16->83:53] +pos_cursor:[83:54] pos_no_white:[83:53] Found pattern:[83:53->83:55] +Ppat_construct ():[83:53->83:55] +Completable: Cpattern Value[v]->variantPayload::Value($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[v] +Path v +[ + { + "detail": "Circle", + "documentation": { + "kind": "markdown", + "value": "```rescript\nCircle\n```\n\n```rescript\ntype shape = Circle | Square\n```" + }, + "insertText": "Circle", + "insertTextFormat": 2, + "kind": 4, + "label": "Circle", + "tags": [] + }, + { + "detail": "Square", + "documentation": { + "kind": "markdown", + "value": "```rescript\nSquare\n```\n\n```rescript\ntype shape = Circle | Square\n```" + }, + "insertText": "Square", + "insertTextFormat": 2, + "kind": 4, + "label": "Square", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 89:23 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Value($0) +Raw opens: 1 A.place holder +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 2 Stdlib CompletionExtensiblePayload +ContextPath Type[attr] +Path attr +[ + { "detail": "bool", "kind": 4, "label": "true", "tags": [] }, + { "detail": "bool", "kind": 4, "label": "false", "tags": [] } +] + +Complete src/CompletionExtensiblePayload.res 92:22 +pos_cursor:[92:22] pos_no_white:[92:21] Found pattern:[92:16->92:23] +Ppat_construct Value:[92:16->92:21] +pos_cursor:[92:22] pos_no_white:[92:21] Found pattern:[92:21->92:23] +Ppat_construct ():[92:21->92:23] +Completable: Cpattern Value[v]->variantPayload::Value($0) +Raw opens: 1 A.place holder +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 2 Stdlib CompletionExtensiblePayload +ContextPath Value[v] +Path v +[ + { "detail": "bool", "kind": 4, "label": "true", "tags": [] }, + { "detail": "bool", "kind": 4, "label": "false", "tags": [] } +] + +Complete src/CompletionExtensiblePayload.res 97:23 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Value($0) +Raw opens: 2 B.place holder ... A.place holder +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 3 Stdlib CompletionExtensiblePayload CompletionExtensiblePayload +ContextPath Type[attr] +Path attr +[ + { + "detail": "color", + "documentation": { + "kind": "markdown", + "value": "```rescript\ntype color = Red | Blue\n```" + }, + "kind": 12, + "label": "None", + "tags": [] + }, + { + "detail": "color", + "documentation": { + "kind": "markdown", + "value": "```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some($0)", + "insertTextFormat": 2, + "kind": 12, + "label": "Some(_)", + "tags": [] + }, + { + "detail": "Red", + "documentation": { + "kind": "markdown", + "value": "```rescript\nRed\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some(Red)", + "insertTextFormat": 2, + "kind": 4, + "label": "Some(Red)", + "tags": [] + }, + { + "detail": "Blue", + "documentation": { + "kind": "markdown", + "value": "```rescript\nBlue\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some(Blue)", + "insertTextFormat": 2, + "kind": 4, + "label": "Some(Blue)", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 100:22 +pos_cursor:[100:22] pos_no_white:[100:21] Found pattern:[100:16->100:23] +Ppat_construct Value:[100:16->100:21] +pos_cursor:[100:22] pos_no_white:[100:21] Found pattern:[100:21->100:23] +Ppat_construct ():[100:21->100:23] +Completable: Cpattern Value[v]->variantPayload::Value($0) +Raw opens: 2 B.place holder ... A.place holder +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 3 Stdlib CompletionExtensiblePayload CompletionExtensiblePayload +ContextPath Value[v] +Path v +[ + { + "detail": "color", + "documentation": { + "kind": "markdown", + "value": "```rescript\ntype color = Red | Blue\n```" + }, + "kind": 12, + "label": "None", + "tags": [] + }, + { + "detail": "color", + "documentation": { + "kind": "markdown", + "value": "```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some(${1:_})", + "insertTextFormat": 2, + "kind": 12, + "label": "Some(_)", + "tags": [] + }, + { + "detail": "Red", + "documentation": { + "kind": "markdown", + "value": "```rescript\nRed\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some(Red)", + "insertTextFormat": 2, + "kind": 4, + "label": "Some(Red)", + "tags": [] + }, + { + "detail": "Blue", + "documentation": { + "kind": "markdown", + "value": "```rescript\nBlue\n```\n\n```rescript\ntype color = Red | Blue\n```" + }, + "insertText": "Some(Blue)", + "insertTextFormat": 2, + "kind": 4, + "label": "Some(Blue)", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 106:23 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Value($0) +Raw opens: 2 B.place holder ... A.place holder +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 3 Stdlib CompletionExtensiblePayload CompletionExtensiblePayload +ContextPath Type[attr] +Path attr +[ + { + "detail": "Small", + "documentation": { + "kind": "markdown", + "value": "```rescript\nSmall\n```\n\n```rescript\ntype size = Small | Large\n```" + }, + "insertText": "Small", + "insertTextFormat": 2, + "kind": 4, + "label": "Small", + "tags": [] + }, + { + "detail": "Large", + "documentation": { + "kind": "markdown", + "value": "```rescript\nLarge\n```\n\n```rescript\ntype size = Small | Large\n```" + }, + "insertText": "Large", + "insertTextFormat": 2, + "kind": 4, + "label": "Large", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 109:22 +pos_cursor:[109:22] pos_no_white:[109:21] Found pattern:[109:16->109:23] +Ppat_construct Value:[109:16->109:21] +pos_cursor:[109:22] pos_no_white:[109:21] Found pattern:[109:21->109:23] +Ppat_construct ():[109:21->109:23] +Completable: Cpattern Value[v]->variantPayload::Value($0) +Raw opens: 2 B.place holder ... A.place holder +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 3 Stdlib CompletionExtensiblePayload CompletionExtensiblePayload +ContextPath Value[v] +Path v +[ + { + "detail": "Small", + "documentation": { + "kind": "markdown", + "value": "```rescript\nSmall\n```\n\n```rescript\ntype size = Small | Large\n```" + }, + "insertText": "Small", + "insertTextFormat": 2, + "kind": 4, + "label": "Small", + "tags": [] + }, + { + "detail": "Large", + "documentation": { + "kind": "markdown", + "value": "```rescript\nLarge\n```\n\n```rescript\ntype size = Small | Large\n```" + }, + "insertText": "Large", + "insertTextFormat": 2, + "kind": 4, + "label": "Large", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 117:18 +XXX Not found! +Completable: Cexpression Type[attr]=P +Raw opens: 2 B.place holder ... A.place holder +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 3 Stdlib CompletionExtensiblePayload CompletionExtensiblePayload +ContextPath Type[attr] +Path attr +[ + { + "detail": "Pair(color, CompletionExtensiblePayloadBase.shape)", + "documentation": { + "kind": "markdown", + "value": "```rescript\nPair(color, CompletionExtensiblePayloadBase.shape)\n```\n\n```rescript\ntype attr = ..\n```" + }, + "insertText": "Pair(${1:_}, ${2:_})", + "insertTextFormat": 2, + "kind": 4, + "label": "Pair(_, _)", + "sortText": "A Pair(_, _)", + "tags": [] + }, + { "detail": "module Promise", "kind": 9, "label": "Promise", "tags": [] }, + { "detail": "module Pair", "kind": 9, "label": "Pair", "tags": [] }, + { + "data": { + "modulePath": "Patterns", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Patterns", + "kind": 9, + "label": "Patterns", + "tags": [] + }, + { + "data": { + "modulePath": "Pervasives", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Pervasives", + "kind": 9, + "label": "Pervasives", + "tags": [] + }, + { + "data": { + "modulePath": "PolyRec", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module PolyRec", + "kind": 9, + "label": "PolyRec", + "tags": [] + }, + { + "data": { + "modulePath": "PrepareRename", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module PrepareRename", + "kind": 9, + "label": "PrepareRename", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_array", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_array", + "kind": 9, + "label": "Primitive_array", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_array_extern", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_array_extern", + "kind": 9, + "label": "Primitive_array_extern", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_bigint", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_bigint", + "kind": 9, + "label": "Primitive_bigint", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_bool", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_bool", + "kind": 9, + "label": "Primitive_bool", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_dict", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_dict", + "kind": 9, + "label": "Primitive_dict", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_exceptions", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_exceptions", + "kind": 9, + "label": "Primitive_exceptions", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_float", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_float", + "kind": 9, + "label": "Primitive_float", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_float_extern", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_float_extern", + "kind": 9, + "label": "Primitive_float_extern", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_hash", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_hash", + "kind": 9, + "label": "Primitive_hash", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_int", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_int", + "kind": 9, + "label": "Primitive_int", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_int_extern", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_int_extern", + "kind": 9, + "label": "Primitive_int_extern", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_js_extern", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_js_extern", + "kind": 9, + "label": "Primitive_js_extern", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_list", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_list", + "kind": 9, + "label": "Primitive_list", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_module", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_module", + "kind": 9, + "label": "Primitive_module", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_object", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_object", + "kind": 9, + "label": "Primitive_object", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_object_extern", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_object_extern", + "kind": 9, + "label": "Primitive_object_extern", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_option", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_option", + "kind": 9, + "label": "Primitive_option", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_promise", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_promise", + "kind": 9, + "label": "Primitive_promise", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_string", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_string", + "kind": 9, + "label": "Primitive_string", + "tags": [] + }, + { + "data": { + "modulePath": "Primitive_string_extern", + "filePath": "src/CompletionExtensiblePayload.res" + }, + "detail": "module Primitive_string_extern", + "kind": 9, + "label": "Primitive_string_extern", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 120:11 +XXX Not found! +Completable: CexhaustiveSwitch Value[v] +Raw opens: 2 B.place holder ... A.place holder +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 3 Stdlib CompletionExtensiblePayload CompletionExtensiblePayload +ContextPath Value[v] +Path v +[ + { + "detail": "CompletionExtensiblePayloadBase.attr", + "kind": 12, + "label": "v", + "tags": [] + }, + { + "detail": "insert exhaustive switch for value", + "filterText": "v", + "insertText": "v {\n | Color(_) => ${1:%todo}\n | Boxed(_) => ${2:%todo}\n | Wrapped(_) => ${3:%todo}\n | Pair(_) => ${4:%todo}\n | Sized(_) => ${5:%todo}\n | A.Value(_) => ${6:%todo}\n | B.Value(_) => ${7:%todo}\n | M.InM(_) => ${8:%todo}\n | Value(_) => ${9:%todo}\n | CompletionExtensiblePayloadBase.Value(_) => ${10:%todo}\n | CompletionExtensiblePayloadBase.Shaped(_) => ${11:%todo}\n | _ => ${12:%todo}\n }", + "insertTextFormat": 2, + "kind": 15, + "label": "v (exhaustive switch)", + "tags": [] + } +] + +Complete src/CompletionExtensiblePayload.res 126:23 +XXX Not found! +Completable: Cexpression Type[attr]->variantPayload::Value($0) +Raw opens: 3 A.place holder ... B.place holder ... A.place holder +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 4 Stdlib CompletionExtensiblePayload CompletionExtensiblePayload CompletionExtensiblePayload +ContextPath Type[attr] +Path attr +[ + { "detail": "bool", "kind": 4, "label": "true", "tags": [] }, + { "detail": "bool", "kind": 4, "label": "false", "tags": [] } +] + +Complete src/CompletionExtensiblePayload.res 129:22 +pos_cursor:[129:22] pos_no_white:[129:21] Found pattern:[129:16->129:23] +Ppat_construct Value:[129:16->129:21] +pos_cursor:[129:22] pos_no_white:[129:21] Found pattern:[129:21->129:23] +Ppat_construct ():[129:21->129:23] +Completable: Cpattern Value[v]->variantPayload::Value($0) +Raw opens: 3 A.place holder ... B.place holder ... A.place holder +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 4 Stdlib CompletionExtensiblePayload CompletionExtensiblePayload CompletionExtensiblePayload +ContextPath Value[v] +Path v +[ + { "detail": "bool", "kind": 4, "label": "true", "tags": [] }, + { "detail": "bool", "kind": 4, "label": "false", "tags": [] } +] + diff --git a/tests/analysis_tests/tests/src/expected/CompletionExtensiblePayloadBase.res.txt b/tests/analysis_tests/tests/src/expected/CompletionExtensiblePayloadBase.res.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/analysis_tests/tests/src/expected/CompletionExtensiblePayloadIface.res.txt b/tests/analysis_tests/tests/src/expected/CompletionExtensiblePayloadIface.res.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/analysis_tests/tests/src/expected/CompletionExtensiblePayloadIface.resi.txt b/tests/analysis_tests/tests/src/expected/CompletionExtensiblePayloadIface.resi.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/analysis_tests/tests/src/expected/CompletionExtensiblePayloadIfaceUse.res.txt b/tests/analysis_tests/tests/src/expected/CompletionExtensiblePayloadIfaceUse.res.txt new file mode 100644 index 00000000000..4d0bd216ac1 --- /dev/null +++ b/tests/analysis_tests/tests/src/expected/CompletionExtensiblePayloadIfaceUse.res.txt @@ -0,0 +1,34 @@ +Complete src/CompletionExtensiblePayloadIfaceUse.res 0:95 +XXX Not found! +Completable: Cexpression Type[CompletionExtensiblePayloadIface, attr]->variantPayload::Toned($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[CompletionExtensiblePayloadIface, attr] +Path CompletionExtensiblePayloadIface.attr +[ + { + "detail": "Light", + "documentation": { + "kind": "markdown", + "value": "```rescript\nLight\n```\n\n```rescript\ntype tone = Light | Dark\n```" + }, + "insertText": "Light", + "insertTextFormat": 2, + "kind": 4, + "label": "Light", + "tags": [] + }, + { + "detail": "Dark", + "documentation": { + "kind": "markdown", + "value": "```rescript\nDark\n```\n\n```rescript\ntype tone = Light | Dark\n```" + }, + "insertText": "Dark", + "insertTextFormat": 2, + "kind": 4, + "label": "Dark", + "tags": [] + } +] + diff --git a/tests/analysis_tests/tests/src/expected/CompletionExtensiblePayloadThird.res.txt b/tests/analysis_tests/tests/src/expected/CompletionExtensiblePayloadThird.res.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/analysis_tests/tests/src/expected/CompletionExtensibleVariant.res.txt b/tests/analysis_tests/tests/src/expected/CompletionExtensibleVariant.res.txt new file mode 100644 index 00000000000..e74d7a10f98 --- /dev/null +++ b/tests/analysis_tests/tests/src/expected/CompletionExtensibleVariant.res.txt @@ -0,0 +1,315 @@ +Complete src/CompletionExtensibleVariant.res 6:26 +XXX Not found! +Completable: Cexpression Type[attr]=Fl +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { + "detail": "Flag", + "documentation": { + "kind": "markdown", + "value": "```rescript\nFlag\n```\n\n```rescript\ntype attr = ..\n```" + }, + "insertText": "Flag", + "insertTextFormat": 2, + "kind": 4, + "label": "Flag", + "sortText": "A Flag", + "tags": [] + }, + { + "detail": "module Float32Array", + "kind": 9, + "label": "Float32Array", + "tags": [] + }, + { + "detail": "module Float64Array", + "kind": 9, + "label": "Float64Array", + "tags": [] + }, + { "detail": "module Float", "kind": 9, "label": "Float", "tags": [] } +] + +Complete src/CompletionExtensibleVariant.res 10:19 +XXX Not found! +Completable: Cexpression Type[attr]=Nu +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { + "detail": "Num(int)", + "documentation": { + "kind": "markdown", + "value": "```rescript\nNum(int)\n```\n\n```rescript\ntype attr = ..\n```" + }, + "insertText": "Num($0)", + "insertTextFormat": 2, + "kind": 4, + "label": "Num(_)", + "sortText": "A Num(_)", + "tags": [] + }, + { "detail": "module Nullable", "kind": 9, "label": "Nullable", "tags": [] }, + { "detail": "module Null", "kind": 9, "label": "Null", "tags": [] } +] + +Hover src/CompletionExtensibleVariant.res 13:19 +{ + "contents": { + "kind": "markdown", + "value": "```rescript\nattr\n```\n\n---\n\n```\n \n```\n```rescript\ntype attr = ..\n```\nGo to: [Type definition](CompletionExtensibleVariant.res#L1,1)\n" + } +} + +Complete src/CompletionExtensibleVariant.res 16:21 +pos_cursor:[16:21] pos_no_white:[16:20] Found pattern:[16:20->16:21] +Ppat_construct S:[16:20->16:21] +Completable: Cpattern Value[value]=S +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[value] +Path value +[ + { + "detail": "Str(string)", + "documentation": { + "kind": "markdown", + "value": "```rescript\nStr(string)\n```\n\n```rescript\ntype attr = ..\n```" + }, + "insertText": "Str(${1:_})", + "insertTextFormat": 2, + "kind": 4, + "label": "Str(_)", + "tags": [] + }, + { + "detail": "Sub.Flag", + "documentation": { + "kind": "markdown", + "value": "```rescript\nSub.Flag\n```\n\n```rescript\ntype attr = ..\n```" + }, + "insertText": "Sub.Flag", + "insertTextFormat": 2, + "kind": 4, + "label": "Sub.Flag", + "tags": [] + }, + { + "detail": "Sub.Toggle(bool)", + "documentation": { + "kind": "markdown", + "value": "```rescript\nSub.Toggle(bool)\n```\n\n```rescript\ntype attr = ..\n```" + }, + "insertText": "Sub.Toggle(${1:_})", + "insertTextFormat": 2, + "kind": 4, + "label": "Sub.Toggle(_)", + "tags": [] + } +] + +Complete src/CompletionExtensibleVariant.res 19:14 +XXX Not found! +Completable: CexhaustiveSwitch Value[valu] +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[valu] +Path valu +[ + { "detail": "attr", "kind": 12, "label": "value", "tags": [] }, + { + "detail": "insert exhaustive switch for value", + "filterText": "value", + "insertText": "value {\n | Str(_) => ${1:%todo}\n | Num(_) => ${2:%todo}\n | Sub.Flag => ${3:%todo}\n | Sub.Toggle(_) => ${4:%todo}\n | _ => ${5:%todo}\n }", + "insertTextFormat": 2, + "kind": 15, + "label": "value (exhaustive switch)", + "tags": [] + } +] + +Complete src/CompletionExtensibleVariant.res 35:17 +pos_cursor:[35:17] pos_no_white:[35:16] Found pattern:[35:16->35:17] +Ppat_construct M:[35:16->35:17] +Completable: Cpattern Value[a]=M +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[a] +Path a +[ + { + "detail": "MoreA", + "documentation": { + "kind": "markdown", + "value": "```rescript\nMoreA\n```\n\n```rescript\ntype t = ..\n```" + }, + "insertText": "MoreA", + "insertTextFormat": 2, + "kind": 4, + "label": "MoreA", + "tags": [] + } +] + +Complete src/CompletionExtensibleVariant.res 38:17 +pos_cursor:[38:17] pos_no_white:[38:16] Found pattern:[38:16->38:17] +Ppat_construct F:[38:16->38:17] +Completable: Cpattern Value[a]=F +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[a] +Path a +[ + { + "detail": "A.FromA", + "documentation": { + "kind": "markdown", + "value": "```rescript\nA.FromA\n```\n\n```rescript\ntype t = ..\n```" + }, + "insertText": "A.FromA", + "insertTextFormat": 2, + "kind": 4, + "label": "A.FromA", + "tags": [] + } +] + +Complete src/CompletionExtensibleVariant.res 41:22 +pos_cursor:[41:22] pos_no_white:[41:21] Found pattern:[41:20->41:22] +Ppat_construct Fl:[41:20->41:22] +Completable: Cpattern Value[value]=Fl +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[value] +Path value +[ + { + "detail": "Sub.Flag", + "documentation": { + "kind": "markdown", + "value": "```rescript\nSub.Flag\n```\n\n```rescript\ntype attr = ..\n```" + }, + "insertText": "Sub.Flag", + "insertTextFormat": 2, + "kind": 4, + "label": "Sub.Flag", + "tags": [] + } +] + +Complete src/CompletionExtensibleVariant.res 45:22 +pos_cursor:[45:22] pos_no_white:[45:21] Found pattern:[45:20->45:22] +Ppat_construct La:[45:20->45:22] +Completable: Cpattern Value[value]=La +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[value] +Path value +Completable: Cpath Value[La] +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[La] +Path La +[ { "detail": "module Lazy", "kind": 9, "label": "Lazy", "tags": [] } ] + +Complete src/CompletionExtensibleVariant.res 51:35 +XXX Not found! +Completable: Cexpression Type[attr]=t->variantPayload::Toggle($0) +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Type[attr] +Path attr +[ + { + "detail": "bool", + "kind": 4, + "label": "true", + "sortText": "A true", + "tags": [] + }, + { + "detail": "'a => Type.t", + "documentation": { + "kind": "markdown", + "value": "\n`typeof(value)` exposes JavaScript's `typeof` operator and returns a `Type.t` enum.\nIt helps you inspect values that come from JavaScript APIs.\n\n## Examples\n\n```rescript\ntypeof(1) == #number\ntypeof(\"a\") == #string\n```\n" + }, + "kind": 12, + "label": "typeof", + "tags": [] + } +] + +Xform src/CompletionExtensibleVariant.res 57:4 +pos_cursor:[55:16] pos_no_white:[55:14] Found expr:[55:9->59:1] +Completable: Cpath Value[value] +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[value] +Path value +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +Hit: Expand catch-all + +TextDocumentEdit: CompletionExtensibleVariant.res +{ + "end": { "character": 3, "line": 57 }, + "start": { "character": 2, "line": 57 } +} +newText: + <--here + Num(_) | Sub.Flag | Sub.Toggle(_) | Later | _ + +Xform src/CompletionExtensibleVariant.res 64:4 +pos_cursor:[62:16] pos_no_white:[62:14] Found expr:[62:9->66:1] +Completable: Cpath Value[optValue] +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[optValue] +Path optValue +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +Hit: Expand catch-all + +TextDocumentEdit: CompletionExtensibleVariant.res +{ + "end": { "character": 3, "line": 64 }, + "start": { "character": 2, "line": 64 } +} +newText: + <--here + Some(Num(_) | Sub.Flag | Sub.Toggle(_) | Later | _) | None + +Xform src/CompletionExtensibleVariant.res start: 69:3, end: 69:8 +found selection: [69:3->69:8] -> [69:3->69:8] +XXX Not found! +Completable: Cpath Value[value] +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[value] +Path value +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +Hit: Exhaustive switch + +TextDocumentEdit: CompletionExtensibleVariant.res +{ + "end": { "character": 8, "line": 69 }, + "start": { "character": 3, "line": 69 } +} +newText: + <--here + switch value { + | Str(_) => %todo + | Num(_) => %todo + | Sub.Flag => %todo + | Sub.Toggle(_) => %todo + | Later => %todo + | _ => %todo + } + diff --git a/tests/analysis_tests/tests/src/expected/CompletionExtensibleVariantUse.res.txt b/tests/analysis_tests/tests/src/expected/CompletionExtensibleVariantUse.res.txt new file mode 100644 index 00000000000..9fde725d063 --- /dev/null +++ b/tests/analysis_tests/tests/src/expected/CompletionExtensibleVariantUse.res.txt @@ -0,0 +1,25 @@ +Complete src/CompletionExtensibleVariantUse.res 4:17 +XXX Not found! +Completable: CexhaustiveSwitch Value[importe] +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[importe] +Path importe +[ + { + "detail": "CompletionExtensibleVariant.attr", + "kind": 12, + "label": "imported", + "tags": [] + }, + { + "detail": "insert exhaustive switch for value", + "filterText": "imported", + "insertText": "imported {\n | CompletionExtensibleVariant.Str(_) => ${1:%todo}\n | CompletionExtensibleVariant.Num(_) => ${2:%todo}\n | CompletionExtensibleVariant.Sub.Flag => ${3:%todo}\n | CompletionExtensibleVariant.Sub.Toggle(_) => ${4:%todo}\n | CompletionExtensibleVariant.Later => ${5:%todo}\n | Local => ${6:%todo}\n | _ => ${7:%todo}\n }", + "insertTextFormat": 2, + "kind": 15, + "label": "imported (exhaustive switch)", + "tags": [] + } +] +