Skip to content

Commit

Permalink
[autocomplete] Correctly render bound type parameters
Browse files Browse the repository at this point in the history
Summary:
Makes autocomplete take into account all type parameters that were in scope at the requested location.

Assumption this relies on:
Even though we render types of identifiers/members from all across the code, we never grab an identifier from underneath a different type-binding site, so it suffices to render all the types with just the type parameters that were in scope at the requested location. (Panagiotis does this assumption seem reasonable?)

Reviewed By: panagosg7

Differential Revision: D18118627

fbshipit-source-id: e1b9e1a9ab285e1c800584a90148f36fe9f115fa
  • Loading branch information
Vijay Ramamurthy authored and facebook-github-bot committed Oct 31, 2019
1 parent 3c53b2c commit e3f2902
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 42 deletions.
63 changes: 36 additions & 27 deletions src/services/autocomplete/autocompleteService_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,8 @@ let autocomplete_member
ac_loc
ac_trigger
docblock
~broader_context =
~broader_context
~tparams =
let ac_loc = loc_of_aloc ~reader ac_loc |> remove_autocomplete_token_from_loc in
let result = Members.extract ~exclude_proto_members cx this in
Hh_json.(
Expand Down Expand Up @@ -248,18 +249,19 @@ let autocomplete_member
let genv = Ty_normalizer_env.mk_genv ~full_cx:cx ~file ~typed_ast ~file_sig in
let rev_result =
SMap.fold
(fun name (_id_loc, t) acc ->
(fun name (_id_loc, type_) acc ->
if (not (autocomplete_is_valid_member name)) || SSet.mem name exclude_keys then
acc
else
let loc = Type.loc_of_t t |> loc_of_aloc ~reader in
((name, loc), t) :: acc)
let loc = Type.loc_of_t type_ |> loc_of_aloc ~reader in
let scheme = Type.TypeScheme.{ tparams; type_ } in
((name, loc), scheme) :: acc)
result_map
[]
in
let result =
rev_result
|> Ty_normalizer.from_types ~options:ty_normalizer_options ~genv
|> Ty_normalizer.from_schemes ~options:ty_normalizer_options ~genv
|> Core_list.rev_filter_map ~f:(function
| ((name, ty_loc), Ok ty) ->
Some
Expand Down Expand Up @@ -321,6 +323,7 @@ let autocomplete_id
~typed_ast
~include_super
~include_this
~tparams
~broader_context =
let ac_loc = loc_of_aloc ~reader ac_loc |> remove_autocomplete_token_from_loc in
let scope_info = Scope_builder.program ((new type_killer reader)#program typed_ast) in
Expand Down Expand Up @@ -365,26 +368,27 @@ let autocomplete_id
SMap.empty
in
let types = collect_types ~reader (LocSet.of_list (SMap.values names_and_locs)) typed_ast in
let normalize_type =
Ty_normalizer.from_type
~options:ty_normalizer_options
~genv:(Ty_normalizer_env.mk_genv ~full_cx:cx ~file:(Context.file cx) ~typed_ast ~file_sig)
in
let (results, errors) =
SMap.fold
(fun name loc (results, errors) ->
match normalize_type (LocMap.find loc types) with
| Ok ty ->
let result =
autocomplete_create_result
~show_func_details:(id_type <> JSXIdent)
(name, ac_loc)
(ty, loc)
in
(result :: results, errors)
| Error error -> (results, error :: errors))
names_and_locs
([], [])
names_and_locs
|> SMap.bindings
|> List.map (fun (name, loc) ->
((name, loc), Type.TypeScheme.{ tparams; type_ = LocMap.find loc types }))
|> Ty_normalizer.from_schemes
~options:ty_normalizer_options
~genv:(Ty_normalizer_env.mk_genv ~full_cx:cx ~file:(Context.file cx) ~typed_ast ~file_sig)
|> List.fold_left
(fun (results, errors) ((name, loc), normalization_result) ->
match normalization_result with
| Ok ty ->
let result =
autocomplete_create_result
~show_func_details:(id_type <> JSXIdent)
(name, ac_loc)
(ty, loc)
in
(result :: results, errors)
| Error error -> (results, error :: errors))
([], [])
in
let json_data_to_log =
Hh_json.(
Expand Down Expand Up @@ -454,6 +458,7 @@ let autocomplete_jsx
ac_loc
ac_trigger
docblock
~tparams
~broader_context =
Flow_js.(
let reason = Reason.mk_reason (Reason.RCustom ac_name) ac_loc in
Expand Down Expand Up @@ -481,13 +486,14 @@ let autocomplete_jsx
ac_loc
ac_trigger
docblock
~tparams
~broader_context)

let autocomplete_get_results
~reader cx file_sig typed_ast trigger_character docblock ~broader_context =
let file_sig = File_sig.abstractify_locs file_sig in
match Autocomplete_js.process_location ~trigger_character ~typed_ast with
| Some (Acid { ac_loc; id_type; include_super; include_this }) ->
| Some (tparams, Acid { ac_loc; id_type; include_super; include_this }) ->
autocomplete_id
~reader
~cx
Expand All @@ -498,8 +504,9 @@ let autocomplete_get_results
~typed_ast
~include_super
~include_this
~tparams
~broader_context
| Some (Acmem (ac_name, ac_loc, this)) ->
| Some (tparams, Acmem (ac_name, ac_loc, this)) ->
autocomplete_member
~reader
~exclude_proto_members:false
Expand All @@ -512,8 +519,9 @@ let autocomplete_get_results
ac_loc
trigger_character
docblock
~tparams
~broader_context
| Some (Acjsx (ac_name, used_attr_names, ac_loc, cls)) ->
| Some (tparams, Acjsx (ac_name, used_attr_names, ac_loc, cls)) ->
autocomplete_jsx
~reader
cx
Expand All @@ -525,6 +533,7 @@ let autocomplete_get_results
ac_loc
trigger_character
docblock
~tparams
~broader_context
| None ->
let json_data_to_log =
Expand Down
23 changes: 10 additions & 13 deletions src/services/autocomplete/autocomplete_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,16 @@ let type_of_jsx_name =
| MemberExpression (_, MemberExpression.{ property = ((_, t), _); _ }) ->
t)

exception Found of autocomplete_type
exception Found of Type.typeparam list * autocomplete_type

class searcher (from_trigger_character : bool) =
object (this)
inherit
[ALoc.t, ALoc.t * Type.t, ALoc.t, ALoc.t * Type.t] Flow_polymorphic_ast_mapper.mapper as super

method on_loc_annot x = x

method on_type_annot x = x
inherit Typed_ast_utils.type_parameter_mapper as super

method find x =
match x with
| Acid _ when from_trigger_character -> ()
| _ -> raise (Found x)
| _ -> this#annot_with_tparams (fun tparams -> raise (Found (tparams, x)))

method! t_identifier (((ac_loc, _), { Flow_ast.Identifier.name; _ }) as ident) =
if is_autocomplete name then
Expand Down Expand Up @@ -148,16 +143,18 @@ class searcher (from_trigger_character : bool) =

method! class_body x =
try super#class_body x
with Found (Acid id) ->
raise (Found (Acid { id with include_super = true; include_this = true }))
with Found (tparams, Acid id) ->
raise (Found (tparams, Acid { id with include_super = true; include_this = true }))

method! function_expression x =
try super#function_expression x
with Found (Acid id) -> raise (Found (Acid { id with include_this = true }))
with Found (tparams, Acid id) ->
raise (Found (tparams, Acid { id with include_this = true }))

method! function_declaration x =
try super#function_declaration x
with Found (Acid id) -> raise (Found (Acid { id with include_this = true }))
with Found (tparams, Acid id) ->
raise (Found (tparams, Acid { id with include_this = true }))
end

let autocomplete_id from_trigger_character _cx ac_name _ac_loc =
Expand All @@ -174,7 +171,7 @@ let process_location ~trigger_character ~typed_ast =
try
ignore ((new searcher (trigger_character <> None))#program typed_ast);
None
with Found res -> Some res
with Found (tparams, res) -> Some (tparams, res)

let autocomplete_set_hooks ~trigger_character =
Type_inference_hooks_js.set_id_hook (autocomplete_id (trigger_character <> None));
Expand Down
11 changes: 11 additions & 0 deletions src/typing/typed_ast_utils.mli
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@
* LICENSE file in the root directory of this source tree.
*)

class type_parameter_mapper :
object
inherit [ALoc.t, ALoc.t * Type.t, ALoc.t, ALoc.t * Type.t] Flow_polymorphic_ast_mapper.mapper

method on_loc_annot : ALoc.t -> ALoc.t

method on_type_annot : ALoc.t * Type.t -> ALoc.t * Type.t

method annot_with_tparams : 'a. (Type.typeparam list -> 'a) -> 'a
end

val find_exact_match_annotation :
(ALoc.t, ALoc.t * Type.t) Flow_ast.program -> ALoc.t -> Type.TypeScheme.t option
(**
Expand Down
4 changes: 2 additions & 2 deletions tests/autocomplete/autocomplete.exp
Original file line number Diff line number Diff line change
Expand Up @@ -3720,7 +3720,7 @@ normalize-1.js = {
"result":[
{
"name":"b",
"type":"mixed",
"type":"T",
"func_details":null,
"path":"normalize-1.js",
"line":3,
Expand Down Expand Up @@ -3814,7 +3814,7 @@ normalize-2.js = {
},
{
"name":"c",
"type":"mixed",
"type":"T",
"func_details":null,
"path":"normalize-2.js",
"line":4,
Expand Down

0 comments on commit e3f2902

Please sign in to comment.