2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the "hack" directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
11 (*****************************************************************************)
12 (* Module determining how long the longest "aliasing chain" of a given
16 * The type-inference algorithm needs to find a fix point when dealing with
19 * Normally, a fix-point should be reached after 2 iterations. However,
20 * there are pathological cases where this is not true.
21 * It happens when the code is aliasing locals, because the type of locals
22 * can change, a 'chain' of aliases can delay the moment where we reach a
30 * // $x will only become an int after 3 iterations.
33 (*****************************************************************************)
38 module Env
= Typing_env
40 (*****************************************************************************)
41 (* Module computing all the aliased locals.
43 * if one writes '$y = $z', then the binding $y => $z is added to the map.
44 * Note that object/class members are counted are counted as locals
45 * (conservatively), because in some cases, they can behave like locals (cf
46 * Typing_env.FakeMembers).
48 (*****************************************************************************)
53 let prev = try SMap.find_unsafe x1 acc
with Not_found
-> [] in
54 SMap.add x1
(x2
:: prev) acc
57 match SMap.get key acc
with
63 inherit [string list
SMap.t
] Nast.Visitor.visitor as parent
65 method! on_expr acc
(_
, e_
as e
) =
68 add local
(Local_id.to_string x
) acc
69 | Obj_get
((_
, (This
| Lvar _
) as x
), (_
, Id
(_
, y
)), _
) ->
70 add local
(Env.FakeMembers.make_id x y
) acc
71 | Class_get
(((), x
), (_
, y
)) ->
72 add local
(Env.FakeMembers.make_static_id x y
) acc
73 | _
-> parent#on_expr acc e
76 let expr local acc e
= (visitor local
)#on_expr acc e
82 type t
= string list
SMap.t
84 val get: string -> t
-> string list
85 val make
: Nast.stmt
-> t
89 type t
= string list
SMap.t
93 let local_to_string = function
95 Some
(Local_id.to_string x
)
96 | Obj_get
((_
, (This
| Lvar _
) as x
), (_
, Id
(_
, y
)), _
) ->
97 Some
(Env.FakeMembers.make_id x y
)
98 | Class_get
(((), x
), (_
, y
)) ->
99 Some
(Env.FakeMembers.make_static_id x y
)
104 inherit [string list
SMap.t
] Nast.Visitor.visitor as parent
106 method! on_expr acc
(_
, e_
as e
) =
108 | Binop
(Ast.Eq _
, (p
, List el
), x2
) ->
109 List.fold_left ~f
:begin fun acc e
->
110 this#on_expr acc
(p
, Binop
(Ast.Eq None
, e
, x2
))
112 | Binop
(Ast.Eq _
, x1
, x2
) ->
113 this#on_assign acc x1 x2
114 | _
-> parent#on_expr acc e
116 method on_assign acc
(_
, e1
) e2
=
117 Option.value_map
(local_to_string e1
) ~f
:begin fun s
->
121 method! on_efun acc _ _
= acc
124 let make st
= visitor#on_stmt
SMap.empty st
128 (*****************************************************************************)
129 (* Given an alias map, returns the length of the longest possible
137 * RESULT=3 because of the chain $x => $y => $z
139 (*****************************************************************************)
142 val get: AliasMap.t
-> int
145 let rec fold aliases
=
146 SMap.fold begin fun k _
(visited
, current_max
) ->
147 let visited, n
= key aliases
visited k
in
148 visited, max n current_max
149 end aliases
(SMap.empty
, 0)
151 and key aliases
visited k
=
152 if SMap.mem k
visited
153 then visited, SMap.find_unsafe k
visited
155 let visited = SMap.add k
0 visited in
156 let kl = AliasMap.get k aliases
in
157 let visited, depth_l
= List.map_env
visited kl (key aliases
) in
158 let my_depth = 1 + List.fold_left ~f
:max ~init
:0 depth_l
in
159 SMap.add k
my_depth visited, my_depth
161 let get aliases
= snd
(fold aliases
)
165 (*****************************************************************************)
167 (*****************************************************************************)
170 let aliases = AliasMap.make st
in
171 let result = Depth.get aliases in
172 (* Needs to be at least 2 because of back edges. *)