Skip to content

Commit

Permalink
[flow][easy] Move finder code to typed_ast_finder
Browse files Browse the repository at this point in the history
Summary:
Moving `type_at_pos_searcher` to typed_ast_finder, which seems appropriate.

This helps prevent some dependency cycles in later diffs.

Changelog: [internal]

Reviewed By: SamChou19815

Differential Revision: D54868848

fbshipit-source-id: dbcb24a5ad4f0aa23998ec60c2b1875f06ff5cfd
  • Loading branch information
panagosg7 authored and facebook-github-bot committed Mar 13, 2024
1 parent f55b7a9 commit 72d7cce
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 143 deletions.
2 changes: 1 addition & 1 deletion src/typing/query_types.ml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*)

module Ast = Flow_ast
open Typed_ast_utils
open Typed_ast_finder

type 'a result =
| FailureNoMatch
Expand Down
2 changes: 1 addition & 1 deletion src/typing/type_annotation.ml
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ module Make (ConsGen : Type_annotation_sig.ConsGen) (Statement : Statement_sig.S
(Error_message.ETSSyntax { kind = Error_message.TSInOutVariance `InOut; loc })
| _ -> ()
);
Typed_ast_finder.polarity variance
Typed_ast_utils.polarity variance

(* Distributive tparam name helpers *)
let use_distributive_tparam_name cx name name_loc tparams_map =
Expand Down
115 changes: 106 additions & 9 deletions src/typing/typed_ast_finder.ml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,6 @@

module Ast = Flow_ast

let polarity = function
| Some (_, { Ast.Variance.kind = Ast.Variance.Plus; comments = _ }) -> Polarity.Positive
| Some (_, { Ast.Variance.kind = Ast.Variance.Minus; comments = _ }) -> Polarity.Negative
| Some (_, Ast.Variance.{ kind = InOut; comments = _ }) -> Polarity.Neutral
| Some (_, Ast.Variance.{ kind = Readonly | Out; comments = _ }) -> Polarity.Positive
| Some (_, Ast.Variance.{ kind = In; comments = _ }) -> Polarity.Negative
| None -> Polarity.Neutral

let mk_bound_t cx tparam = Flow_js_utils.generic_of_tparam cx ~f:(fun x -> x) tparam

class type_parameter_mapper =
Expand Down Expand Up @@ -56,7 +48,7 @@ class type_parameter_mapper =
| None -> None
| Some ((_, t), _) -> Some t
in
let polarity = polarity variance in
let polarity = Typed_ast_utils.polarity variance in
{ Type.reason; name = Subst_name.Name name; bound; polarity; default; is_this = false }

(* Record and restore the parameter environment around nodes that might
Expand Down Expand Up @@ -177,3 +169,108 @@ module ExactMatchQuery = struct
end

let find_exact_match_annotation = ExactMatchQuery.find

(* Find identifier under location *)
module Type_at_pos = struct
exception Found of ALoc.t * bool * Type.t

(* Kinds of nodes that "type-at-pos" is interested in:
* - identifiers (handled in t_identifier)
* - type parameters (handled in type_param_identifier)
* - literal object keys (handled in object_key)
* - `this`, `super` (handled in expression)
* - private property names (handled in expression)
*)
class type_at_pos_searcher cx (target_loc : Loc.t) =
object (self)
inherit type_parameter_mapper as super

method covers_target loc = Reason.in_range target_loc (ALoc.to_loc_exn loc)

method find_loc
: 'a. ALoc.t -> Type.t -> is_type_identifier:bool -> tparams_rev:Type.typeparam list -> 'a
=
(fun loc t ~is_type_identifier ~tparams_rev:_ -> raise (Found (loc, is_type_identifier, t)))

method! t_identifier (((loc, t), _) as id) =
if self#covers_target loc then
self#annot_with_tparams (self#find_loc loc t ~is_type_identifier:false)
else
super#t_identifier id

method! type_identifier_reference (((loc, t), _) as id) =
if self#covers_target loc then
self#annot_with_tparams (self#find_loc loc t ~is_type_identifier:true)
else
super#t_identifier id

method! jsx_identifier (((loc, t), _) as id) =
if self#covers_target loc then
self#annot_with_tparams (self#find_loc loc t ~is_type_identifier:false)
else
super#jsx_identifier id

method! type_param ((_, { Ast.Type.TypeParam.name = (loc, _); _ }) as tparam) =
if self#covers_target loc then (
let tparam = self#make_typeparam tparam in
rev_bound_tparams <- tparam :: rev_bound_tparams;
self#annot_with_tparams
(self#find_loc loc (mk_bound_t cx tparam) ~is_type_identifier:false)
) else
super#type_param tparam

method! object_key key =
let open Ast.Expression.Object.Property in
match key with
| StringLiteral ((loc, t), _)
| NumberLiteral ((loc, t), _)
| BigIntLiteral ((loc, t), _)
when self#covers_target loc ->
self#annot_with_tparams (self#find_loc loc t ~is_type_identifier:false)
| _ -> super#object_key key

method! expression expr =
let open Ast.Expression in
match expr with
| ((loc, t), (This _ | Super _))
| ((_, t), Member { Member.property = Member.PropertyPrivateName (loc, _); _ })
| ( (_, t),
OptionalMember
{
OptionalMember.member = { Member.property = Member.PropertyPrivateName (loc, _); _ };
_;
}
)
when self#covers_target loc ->
self#annot_with_tparams (self#find_loc loc t ~is_type_identifier:false)
| _ -> super#expression expr

method! implicit (((loc, t), _) as impl) =
if self#covers_target loc then
self#annot_with_tparams (self#find_loc loc t ~is_type_identifier:false)
else
super#implicit impl

method! jsx_attribute_name_identifier (((loc, _), _) as id) =
if self#covers_target loc then
let reason = Reason.mk_reason (Reason.RCustom "jsx attr") loc in
let (_, lazy_hint) = Type_env.get_hint cx loc in
lazy_hint reason
|> Type_hint.with_hint_result
~ok:(fun t ->
self#annot_with_tparams (self#find_loc loc t ~is_type_identifier:false))
~error:(fun () -> super#jsx_attribute_name_identifier id)
else
super#jsx_attribute_name_identifier id
end

let find cx typed_ast loc =
let searcher = new type_at_pos_searcher cx loc in
try
ignore (searcher#program typed_ast);
None
with
| Found (loc, is_type_id, scheme) -> Some (ALoc.to_loc_exn loc, is_type_id, scheme)
end

let find_type_at_pos_annotation = Type_at_pos.find
133 changes: 20 additions & 113 deletions src/typing/typed_ast_utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -5,135 +5,42 @@
* LICENSE file in the root directory of this source tree.
*)

module Ast = Flow_ast
module ALocMap = Loc_collections.ALocMap
open Typed_ast_finder

(* Find identifier under location *)
module Type_at_pos = struct
exception Found of ALoc.t * bool * Type.t

(* Kinds of nodes that "type-at-pos" is interested in:
* - identifiers (handled in t_identifier)
* - type parameters (handled in type_param_identifier)
* - literal object keys (handled in object_key)
* - `this`, `super` (handled in expression)
* - private property names (handled in expression)
*)
class type_at_pos_searcher cx (target_loc : Loc.t) =
object (self)
inherit type_parameter_mapper as super

method covers_target loc = Reason.in_range target_loc (ALoc.to_loc_exn loc)

method find_loc
: 'a. ALoc.t -> Type.t -> is_type_identifier:bool -> tparams_rev:Type.typeparam list -> 'a
=
(fun loc t ~is_type_identifier ~tparams_rev:_ -> raise (Found (loc, is_type_identifier, t)))

method! t_identifier (((loc, t), _) as id) =
if self#covers_target loc then
self#annot_with_tparams (self#find_loc loc t ~is_type_identifier:false)
else
super#t_identifier id

method! type_identifier_reference (((loc, t), _) as id) =
if self#covers_target loc then
self#annot_with_tparams (self#find_loc loc t ~is_type_identifier:true)
else
super#t_identifier id

method! jsx_identifier (((loc, t), _) as id) =
if self#covers_target loc then
self#annot_with_tparams (self#find_loc loc t ~is_type_identifier:false)
else
super#jsx_identifier id

method! type_param ((_, { Ast.Type.TypeParam.name = (loc, _); _ }) as tparam) =
if self#covers_target loc then (
let tparam = self#make_typeparam tparam in
rev_bound_tparams <- tparam :: rev_bound_tparams;
self#annot_with_tparams
(self#find_loc loc (mk_bound_t cx tparam) ~is_type_identifier:false)
) else
super#type_param tparam

method! object_key key =
let open Ast.Expression.Object.Property in
match key with
| StringLiteral ((loc, t), _)
| NumberLiteral ((loc, t), _)
| BigIntLiteral ((loc, t), _)
when self#covers_target loc ->
self#annot_with_tparams (self#find_loc loc t ~is_type_identifier:false)
| _ -> super#object_key key

method! expression expr =
let open Ast.Expression in
match expr with
| ((loc, t), (This _ | Super _))
| ((_, t), Member { Member.property = Member.PropertyPrivateName (loc, _); _ })
| ( (_, t),
OptionalMember
{
OptionalMember.member = { Member.property = Member.PropertyPrivateName (loc, _); _ };
_;
}
)
when self#covers_target loc ->
self#annot_with_tparams (self#find_loc loc t ~is_type_identifier:false)
| _ -> super#expression expr

method! implicit (((loc, t), _) as impl) =
if self#covers_target loc then
self#annot_with_tparams (self#find_loc loc t ~is_type_identifier:false)
else
super#implicit impl

method! jsx_attribute_name_identifier (((loc, _), _) as id) =
if self#covers_target loc then
let reason = Reason.mk_reason (Reason.RCustom "jsx attr") loc in
let (_, lazy_hint) = Type_env.get_hint cx loc in
lazy_hint reason
|> Type_hint.with_hint_result
~ok:(fun t ->
self#annot_with_tparams (self#find_loc loc t ~is_type_identifier:false))
~error:(fun () -> super#jsx_attribute_name_identifier id)
else
super#jsx_attribute_name_identifier id
end

let find cx typed_ast loc =
let searcher = new type_at_pos_searcher cx loc in
try
ignore (searcher#program typed_ast);
None
with
| Found (loc, is_type_id, scheme) -> Some (ALoc.to_loc_exn loc, is_type_id, scheme)
end

let find_type_at_pos_annotation = Type_at_pos.find

class type_at_aloc_map_folder =

let polarity = function
| Some (_, { Ast.Variance.kind = Ast.Variance.Plus; comments = _ }) -> Polarity.Positive
| Some (_, { Ast.Variance.kind = Ast.Variance.Minus; comments = _ }) -> Polarity.Negative
| Some (_, Ast.Variance.{ kind = InOut; comments = _ }) -> Polarity.Neutral
| Some (_, Ast.Variance.{ kind = Readonly | Out; comments = _ }) -> Polarity.Positive
| Some (_, Ast.Variance.{ kind = In; comments = _ }) -> Polarity.Negative
| None -> Polarity.Neutral

class ['M, 'T, 'N, 'U] type_at_aloc_map_folder =
object
inherit type_parameter_mapper
inherit ['M, 'M * 'T, 'N, 'N * 'U] Flow_polymorphic_ast_mapper.mapper

val mutable map = ALocMap.empty

method! on_type_annot x =
method on_loc_annot x = x

method on_type_annot x =
let (loc, t) = x in
map <- ALocMap.add loc t map;
x

method to_map = map
end

class type_at_aloc_list_folder =
class ['M, 'T, 'N, 'U] type_at_aloc_list_folder =
object
inherit type_parameter_mapper
inherit ['M, 'M * 'T, 'N, 'N * 'U] Flow_polymorphic_ast_mapper.mapper

val mutable l = []

method! on_type_annot x =
method on_loc_annot x = x

method on_type_annot x =
let (loc, t) = x in
l <- (loc, t) :: l;
x
Expand Down
20 changes: 1 addition & 19 deletions src/typing/typed_ast_utils.mli
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,7 @@
* LICENSE file in the root directory of this source tree.
*)

(**
* Find the first typed AST entry for "type-at-pos" related queries. A query
* succeeds if the location is within the range of a symbol in the AST. The kinds
* of symbols handled here are:
* - identifiers
* - literal object keys
* - `this`, `super`
* - private property names
*
* The first part of the return is the full span of the matching symbol.
*
* It's convenient to use Loc.t as the input query, since this is usually called
* in direct response to a client query, which are typically concrete locations.
*)
val find_type_at_pos_annotation :
Context.t ->
(ALoc.t, ALoc.t * Type.t) Flow_ast.Program.t ->
Loc.t ->
(Loc.t * bool * Type.t) option
val polarity : 'L Flow_ast.Variance.t option -> Polarity.t

val typed_ast_to_map :
(ALoc.t, ALoc.t * Type.t) Flow_polymorphic_ast_mapper.Ast.Program.t ->
Expand Down

0 comments on commit 72d7cce

Please sign in to comment.