Permalink
Browse files

Change Tast.ExprAnnotation.t from Pos.t * ty option to Pos.t * ty

Summary:
The TAST now annotates every expression with a type, so we are free to make that type mandatory.

This makes consuming the TAST much easier--it is no longer necessary to handle `None` cases, and consumers need not worry about implicitly typed nodes.

Reviewed By: pittsw

Differential Revision: D7495917

fbshipit-source-id: 55e93f9ae28da83b2d972b5b996747143863d450
  • Loading branch information...
Jake Bailey authored and hhvm-bot committed Apr 12, 2018
1 parent b923c30 commit eeee8123e16811c39b8400b2b0c47f230e83b1e1
Showing with 595 additions and 658 deletions.
  1. +1 −4 hphp/hack/src/hh_single_type_check.ml
  2. +2 −2 hphp/hack/src/server/identifySymbolService.ml
  3. +13 −14 hphp/hack/src/server/serverInferType.ml
  4. +4 −4 hphp/hack/src/server/symbolFunCallService.ml
  5. +8 −11 hphp/hack/src/server/symbolTypeService.ml
  6. +9 −20 hphp/hack/src/typing/tast.ml
  7. +1 −2 hphp/hack/src/typing/tast_expand.ml
  8. +1 −3 hphp/hack/src/typing/tast_type_collector.ml
  9. +2 −6 hphp/hack/src/typing/typing.ml
  10. +5 −5 hphp/hack/src/typing/typing_mutability.ml
  11. +35 −38 hphp/hack/test/tast/add_vector.php.exp
  12. +4 −4 hphp/hack/test/tast/arith_plus.php.exp
  13. +62 −64 hphp/hack/test/tast/array_filter.php.exp
  14. +33 −35 hphp/hack/test/tast/array_map.php.exp
  15. +14 −14 hphp/hack/test/tast/array_order.php.exp
  16. +4 −4 hphp/hack/test/tast/assert.php.exp
  17. +21 −21 hphp/hack/test/tast/async_lambda.php.exp
  18. +4 −4 hphp/hack/test/tast/call_args.php.exp
  19. +4 −4 hphp/hack/test/tast/class_get.php.exp
  20. +18 −18 hphp/hack/test/tast/dynamic_member_access.php.exp
  21. +28 −34 hphp/hack/test/tast/eq_op.php.exp
  22. +7 −7 hphp/hack/test/tast/fake_member.php.exp
  23. +20 −23 hphp/hack/test/tast/foreach_ref.php.exp
  24. +12 −14 hphp/hack/test/tast/fun_meth_variadic.php.exp
  25. +23 −28 hphp/hack/test/tast/lambda1.php.exp
  26. +6 −7 hphp/hack/test/tast/lambda_contextual.php.exp
  27. +36 −38 hphp/hack/test/tast/lambda_efun.php.exp
  28. +15 −15 hphp/hack/test/tast/multiple_type.php.exp
  29. +10 −11 hphp/hack/test/tast/null_check.php.exp
  30. +4 −4 hphp/hack/test/tast/null_coalesce.php.exp
  31. +5 −5 hphp/hack/test/tast/parent_construct.php.exp
  32. +37 −39 hphp/hack/test/tast/pseudofunctions.php.exp
  33. +8 −10 hphp/hack/test/tast/ret_by_ref.php.exp
  34. +22 −22 hphp/hack/test/tast/shapes_special_functions.php.exp
  35. +6 −7 hphp/hack/test/tast/singleton_unresolved_function_call.php.exp
  36. +45 −50 hphp/hack/test/tast/switch_fallthrough.php.exp
  37. +16 −17 hphp/hack/test/tast/try_catch.php.exp
  38. +3 −3 hphp/hack/test/tast/typedef.php.exp
  39. +1 −1 hphp/hack/test/tast/unbound_global.php.exp
  40. +21 −21 hphp/hack/test/tast/unresolved_grown_after_lambda.php.exp
  41. +1 −1 hphp/hack/test/tast/unsafe_block.php.exp
  42. +11 −11 hphp/hack/test/tast/using.php.exp
  43. +13 −13 hphp/hack/test/tast/xhp.php.exp
@@ -823,10 +823,7 @@ let handle_mode
TASTStringMapper.map_program tast
~map_env_annotation:(fun () -> ())
~map_expr_annotation:begin fun () (pos, ty) ->
match ty with
| None -> Format.asprintf "(%a, None)" Pos.pp pos
| Some ty ->
Format.asprintf "(%a, Some %s)" Pos.pp pos (Typing_print.full env ty)
Format.asprintf "(%a, %s)" Pos.pp pos (Typing_print.full env ty)
end
~map_class_id_annotation:(fun () -> Typing_print.full env)
in
@@ -182,7 +182,7 @@ class ['self] visitor = object (self : 'self)
match snd expr with
| Tast.New ((ty, _), _, _) ->
typed_constructor env ty pos
| Tast.Obj_get (((_, Some ty), _), (_, Tast.Id mid), _) ->
| Tast.Obj_get (((_, ty), _), (_, Tast.Id mid), _) ->
typed_property env ty mid
| Tast.Class_const ((ty, _), mid) ->
typed_const env ty mid
@@ -219,7 +219,7 @@ class ['self] visitor = object (self : 'self)
match snd e with
| Tast.Id id ->
process_fun_id id
| Tast.Obj_get (((_, Some ty), _) as obj, (_, Tast.Id mid), _) ->
| Tast.Obj_get (((_, ty), _) as obj, (_, Tast.Id mid), _) ->
self#on_expr env obj + typed_method env ty mid
| Tast.Class_const ((ty, _) as cid, mid) ->
self#on_class_id env cid + typed_method env ty mid
@@ -10,17 +10,16 @@
open Hh_core
open Option.Monad_infix
(** Return the type of the smallest typed expression node whose associated span
(** Return the type of the smallest expression node whose associated span
* (the Pos.t in its Tast.ExprAnnotation.t) contains the given position.
* "Smallest" here refers to the size of the node's associated span, in terms of
* its byte length in the original source file. "Typed" means that the Tast.ty
* option in the expression's Tast.ExprAnnotation.t is not None.
* its byte length in the original source file.
*
* If there is no single smallest node (i.e., multiple typed expression nodes
* have spans of the same length containing the given position, where that
* length is less than the length of all other spans containing the given
* position), return the type of the first of these nodes visited in a preorder
* traversal of the Tast.
* If there is no single smallest node (i.e., multiple expression nodes have
* spans of the same length containing the given position, where that length is
* less than the length of all other spans containing the given position),
* return the type of the first of these nodes visited in a preorder traversal
* of the Tast.
*
* This choice is somewhat arbitrary, and would seem to be unnecessary at first
* blush (and indeed would be in a concrete syntax tree). In most situations,
@@ -67,7 +66,7 @@ class ['self] base_visitor line char = object (self : 'self)
method! on_expr_annotation env (pos, ty) =
if Pos.inside pos line char
then ty >>| fun ty -> pos, env, ty
then Some (pos, env, ty)
else None
method! on_class_id env cid =
@@ -88,10 +87,10 @@ end
(** Same as `base_visitor`, except:
If the smallest typed expression containing the given position has a
function type and is being invoked in a Call expression, return that
function's return type rather than the type of the function (i.e., the type
of the expression returned by the Call expression).
If the smallest expression containing the given position has a function type
and is being invoked in a Call expression, return that function's return
type rather than the type of the function (i.e., the type of the expression
returned by the Call expression).
*)
class ['self] function_following_visitor line char = object (self : 'self)
@@ -145,7 +144,7 @@ class ['self] range_visitor startl startc endl endc = object (_ : 'self)
method merge x _ = x
method! on_expr_annotation env (pos, ty) =
if Pos.exactly_matches_range pos startl startc endl endc
then ty >>| fun ty -> env, ty
then Some (env, ty)
else None
end
@@ -74,14 +74,14 @@ class ['self] visitor = object (self : 'self)
method! on_expr env (((pos, ty), expr_) as expr) =
let acc =
match expr_ with
| Tast.New _ when Option.is_some ty ->
| Tast.New _ ->
let mid = (pos, SN.Members.__construct) in
Typing_utils.get_class_ids env (Utils.unsafe_opt ty)
Typing_utils.get_class_ids env ty
|> List.map ~f:(fun cid -> self#method_call env Constructor cid mid)
|> List.fold ~init:self#zero ~f:self#plus
| Tast.Fun_id (pos, name) ->
self#fun_call env Function name pos
| Tast.Method_id (((_, Some ty), _), mid) ->
| Tast.Method_id (((_, ty), _), mid) ->
Typing_utils.get_class_ids env ty
|> List.map ~f:(fun cid -> self#method_call env Method cid mid)
|> List.fold ~init:self#zero ~f:self#plus
@@ -109,7 +109,7 @@ class ['self] visitor = object (self : 'self)
| Tast.Id (pos, name) ->
self#fun_call env Function name pos
| Tast.Class_const ((ty, _), mid)
| Tast.Obj_get (((_, Some ty), _), (_, Tast.Id mid), _) ->
| Tast.Obj_get (((_, ty), _), (_, Tast.Id mid), _) ->
let target_type =
if snd mid = SN.Members.__construct then Constructor else Method in
Typing_utils.get_class_ids env ty
@@ -24,9 +24,9 @@ class ['self] visitor = object (self : 'self)
method! on_expr env (((pos, ty), expr_) as expr) =
let acc =
match expr_, ty with
| Tast.Lvar (_, id), Some ty
| Tast.Dollardollar (_, id), Some ty ->
match expr_ with
| Tast.Lvar (_, id)
| Tast.Dollardollar (_, id) ->
Result_set.singleton {
pos = Pos.to_relative_string pos;
type_ = Typing_print.full_strip_ns env ty;
@@ -39,14 +39,11 @@ class ['self] visitor = object (self : 'self)
method! on_fun_param env param =
let acc =
let (pos, ty) = param.Tast.param_annotation in
match ty with
| Some ty ->
Result_set.singleton {
pos = Pos.to_relative_string pos;
type_ = Typing_print.full_strip_ns env ty;
ident_ = Local_id.to_int (Local_id.get param.Tast.param_name);
}
| None -> self#zero
Result_set.singleton {
pos = Pos.to_relative_string pos;
type_ = Typing_print.full_strip_ns env ty;
ident_ = Local_id.to_int (Local_id.get param.Tast.param_name);
}
in
self#plus acc @@ super#on_fun_param env param
end
@@ -14,13 +14,6 @@
*)
type ty = Typing_defs.locl Typing_defs.ty
let pp_ty_option fmt = function
| None -> Format.pp_print_string fmt "None"
| Some ty ->
Format.pp_print_string fmt "(Some ";
Pp_type.pp_ty fmt ty;
Format.pp_print_string fmt ")"
type saved_env = {
tcopt : TypecheckerOptions.t;
tenv : ty IMap.t;
@@ -53,11 +46,9 @@ let pp_saved_env fmt env =
Format.fprintf fmt " }@]"
(* Typed AST.
* We re-use the NAST but annotate expressions with position *and*
* type not just position. The type is optional, the idea being that *if*
* present then it should be correct according to the typing rules, and if
* absent it should be cheaply and uniquely derivable from the subexpressions,
* given particular types for local variables.
*
* We re-use the NAST, but annotate expressions with position *and* type, not
* just position.
*
* Going forward, we will need further annotations
* such as type arguments to generic methods and `new`, annotations on locals
@@ -70,12 +61,12 @@ let pp_saved_env fmt env =
*)
module Annotations = struct
module ExprAnnotation = struct
type t = Pos.t * ty option
type t = Pos.t * ty
let pp fmt (pos, ty) =
Format.fprintf fmt "(@[";
Pos.pp fmt pos;
Format.fprintf fmt ",@ ";
pp_ty_option fmt ty;
Pp_type.pp_ty fmt ty;
Format.fprintf fmt "@])"
end
@@ -99,7 +90,7 @@ include TypeAndPosAnnotatedAST
* some abstraction in so that we can change the representation (e.g. put
* further annotations on the expression) as we see fit.
*)
let make_expr_annotation p ty : Annotations.ExprAnnotation.t = (p, Some ty)
let make_expr_annotation p ty : Annotations.ExprAnnotation.t = (p, ty)
(* Helper function to create a typed and positioned expression.
* Do not construct this triple directly - at some point we will build
@@ -108,10 +99,8 @@ let make_expr_annotation p ty : Annotations.ExprAnnotation.t = (p, Some ty)
*)
let make_typed_expr p ty te : expr = (make_expr_annotation p ty, te)
(* Given types for locals, the type of the expression should be cheaply
* and uniquely derivable.
*)
let make_implicitly_typed_expr p te : expr = ((p, None), te)
(* Get the position of an expression *)
let get_position (((p, _), _) : expr) = p
(* Get the type of an expression *)
let get_type (((_, ty), _) : expr) = ty
@@ -101,8 +101,7 @@ let expand_ty env ty =
and exp_where_constraint (ty1, ck, ty2) = (exp_ty ty1, ck, exp_ty ty2) in
exp_ty ty
let expand_annotation env (pos, tyopt) =
(pos, Option.map tyopt (expand_ty env))
let expand_annotation env (pos, ty) = (pos, expand_ty env ty)
class ['self] expander = object (_ : 'self)
inherit [_] Tast_visitor.endo
@@ -15,9 +15,7 @@ class ['self] type_collector = object (_ : 'self)
method zero = Pos.AbsolutePosMap.empty
method plus = Pos.AbsolutePosMap.union ~combine:(fun _ a b -> Some (a @ b))
method! on_expr_annotation env (p,ty) =
match ty with
| Some ty -> Pos.AbsolutePosMap.singleton (Pos.to_absolute p) [Typing_print.to_json env ty]
| None -> Pos.AbsolutePosMap.empty
Pos.AbsolutePosMap.singleton (Pos.to_absolute p) [Typing_print.to_json env ty]
method! on_class_id env (ty,cid) =
match cid with
| Tast.CI ((p,_),_) ->
@@ -588,9 +588,7 @@ and check_using_clause env has_await ((pos, content) as using_clause) =
| Expr_list using_clauses ->
let env, pairs = List.map_env env using_clauses (check_using_expr has_await) in
let typed_using_clauses, vars_list = List.unzip pairs in
let ty_ =
try Ttuple (List.map typed_using_clauses (fun ((_,ty),_) -> unsafe_opt ty)) with
| _ -> TUtils.tany env in
let ty_ = Ttuple (List.map typed_using_clauses T.get_type) in
let ty = (Reason.Rnone, ty_) in
env, T.make_typed_expr pos ty (T.Expr_list typed_using_clauses),
List.concat vars_list
@@ -2290,7 +2288,7 @@ and expr_
let env, te, ty = expr env e in
let rec check_types env = function
| _, T.Lvar _ -> ()
| _, T.Array_get (((_, Some ty1), _) as te1, Some _) ->
| _, T.Array_get (((_, ty1), _) as te1, Some _) ->
let rec iter = function
| _, Tany -> true
| _, Tprim Tstring -> true
@@ -2307,8 +2305,6 @@ and expr_
let msgl = Reason.to_string ("This is " ^ ty_str) (fst ety1) in
Errors.inout_argument_bad_type (fst e) msgl
end
| _, T.Array_get (te2, Some _) ->
check_types env te2
(* Other invalid expressions are caught in NastCheck. *)
| _ -> ()
in
@@ -30,8 +30,8 @@ let rec expr_returns_owned_mutable
| T.Call (_, (_, T.Id id), _, _, _)
| T.Call (_, (_, T.Fun_id id), _, _, _) ->
fun_returns_mutable env id
| T.Call (_, ((_, (Some (_, Tfun fty))), T.Obj_get _), _, _, _)
| T.Call (_, ((_, (Some (_, Tfun fty))), T.Class_const _), _, _, _)->
| T.Call (_, ((_, (_, Tfun fty)), T.Obj_get _), _, _, _)
| T.Call (_, ((_, (_, Tfun fty)), T.Class_const _), _, _, _)->
fty.ft_returns_mutable
(* conditional operator returns owned mutable if both consequence and alternative
return owned mutable *)
@@ -194,7 +194,7 @@ let enforce_mutable_call (env : Typing_env.env) (te : T.expr) =
| None -> ()
end
(* $x->method() where method is mutable *)
| T.Call (_, ((pos, (Some (r, Tfun fty))), T.Obj_get (expr, _, _)), _, el, _) ->
| T.Call (_, ((pos, (r, Tfun fty)), T.Obj_get (expr, _, _)), _, el, _) ->
(if fty.ft_mutable && not (expr_is_mutable env expr) then
Env.error_if_reactive_context env @@ begin fun () ->
let fpos = Reason.to_pos r in
@@ -220,9 +220,9 @@ let rec is_byval_collection_type env ty =
let rec is_byval_collection_value env v =
match v with
| (_, Some ty), T.Lvar _ ->
| (_, ty), T.Lvar _ ->
is_byval_collection_type env ty
| (_, Some ty), T.Array_get (e, _) ->
| (_, ty), T.Array_get (e, _) ->
is_byval_collection_type env ty &&
is_byval_collection_value env e
| _ -> false
Oops, something went wrong.

0 comments on commit eeee812

Please sign in to comment.