2 * Copyright (c) 2016, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
11 module Env
= Typing_env
15 (*****************************************************************************)
16 (* Logging type inference environment *)
17 (*****************************************************************************)
19 (* Eventual input to Tty.cprint *)
20 let out_channel = ref stdout
21 let logBuffer = ref []
22 let indentLevel = ref 0
23 let accumulatedLength = ref 0
29 cprint ~
out_channel:!out_channel ~color_mode
:Color_Auto
30 ((Normal White
, String.make
(2 * !indentLevel) ' '
) ::
31 List.rev
((Normal White
, "\n") :: !logBuffer));
32 accumulatedLength := 0;
37 Printf.ksprintf
(fun s
->
38 let len = String.length s
in
39 logBuffer := (c
,s
) :: !logBuffer;
40 if !accumulatedLength + len > 80
42 else accumulatedLength := !accumulatedLength + len)
44 let indentEnv ?
(color
=Normal Yellow
) message f
=
46 lprintf color
"%s" message
;
48 indentLevel := !indentLevel + 1;
51 indentLevel := !indentLevel - 1
53 (* Most recent environment. We only display diffs *)
54 let lastenv =ref (Env.empty
TypecheckerOptions.default
55 Relative_path.default None
)
56 let iterations: int Pos.Map.t
ref = ref Pos.Map.empty
58 (* Log all changes to subst *)
59 let log_subst_diff oldSubst newSubst
=
60 indentEnv (Printf.sprintf
61 "subst(changes; old size = %d; new size = %d; size change = %d)"
62 (IMap.cardinal oldSubst
) (IMap.cardinal newSubst
)
63 (IMap.cardinal newSubst
- IMap.cardinal oldSubst
))
66 IMap.iter
(fun n n'
->
67 match IMap.get n oldSubst
with
70 lprintf (Bold Green
) "#%d: " n
;
71 lprintf (Normal Green
) "#%d; " n'
78 lprintf (Bold Green
) "#%d: " n'
;
79 lprintf (Normal Green
) "#%d; " n'
82 IMap.iter
(fun n _n'
->
83 if IMap.mem n newSubst
then ()
84 else lprintf (Normal Red
) "#%d deleted; " n
) oldSubst
87 (* Log all changes to tenv *)
88 let log_tenv_diff oldEnv newEnv
=
89 indentEnv (Printf.sprintf
90 "tenv(changes; old size = %d; new size = %d; size change = %d)"
91 (IMap.cardinal oldEnv
.Env.tenv
) (IMap.cardinal newEnv
.Env.tenv
)
92 (IMap.cardinal newEnv
.Env.tenv
- IMap.cardinal oldEnv
.Env.tenv
))
96 match IMap.get n oldEnv
.Env.tenv
with
99 lprintf (Bold Green
) "#%d: " n
;
100 lprintf (Normal Green
) "%s; " (Typing_print.full newEnv t
)
107 lprintf (Bold Green
) "#%d: " n
;
108 lprintf (Normal Green
) "%s; " (Typing_print.full newEnv t'
)
111 IMap.iter
(fun n _
->
112 if IMap.mem n newEnv
.Env.tenv
then ()
113 else lprintf (Normal Red
) "#%d deleted; " n
) oldEnv
.Env.tenv
116 (* Dump the diff between oldEnv and newEnv. TODO: lenv component *)
117 let log_env_diff oldEnv newEnv
=
119 log_subst_diff oldEnv
.Env.subst newEnv
.Env.subst
;
120 log_tenv_diff oldEnv newEnv
;
124 let rec log_type_list env tyl
=
128 lprintf (Normal Green
) "%s" (Typing_print.debug env ty
)
130 lprintf (Normal Green
) "%s, " (Typing_print.debug env ty
);
131 log_type_list env tyl
133 let log_continuation env name cont
=
134 indentEnv (Typing_continuations.to_string name
) (fun () ->
135 Local_id.Map.iter
begin fun id
(type_
, expr_id
) ->
137 lprintf (Bold Green
) "%s[#%d]: "
138 (Local_id.get_name id
) (Local_id.to_int id
);
139 lprintf (Normal Green
) "%s" (Typing_print.debug env type_
);
140 lprintf (Normal Green
) " [eid: %s]" (Ident.debug expr_id
) end
143 let log_local_types env
=
144 indentEnv "local_types" (fun () ->
145 Typing_continuations.Map.iter
146 (log_continuation env
)
147 env
.Env.lenv
.Env.local_types
)
149 let log_using_vars env
=
150 let using_vars = env
.Env.lenv
.Env.local_using_vars
in
151 if not
(Local_id.Set.is_empty
using_vars) then
152 indentEnv "using_vars" (fun () ->
153 Local_id.Set.iter
(fun lvar
->
154 lprintf (Normal Green
) "%s " (Local_id.get_name lvar
))
157 let log_return_type env
=
158 indentEnv "return_type" (fun () ->
159 let Typing_env_return_info.
160 {return_type
; return_disposable
; return_mutable
; return_explicit
;
161 return_void_to_rx
; } = Env.get_return env
in
162 lprintf (Normal Green
) "%s%s%s%s%s"
163 (Typing_print.debug env return_type
)
164 (if return_disposable
then " (disposable)" else "")
165 (if return_mutable
then " (mutable_return)" else "")
166 (if return_explicit
then " (explicit)" else "")
167 (if return_void_to_rx
then " (void_to_rx)" else "")
171 let tparams = Env.get_generic_parameters env
in
172 if not
(List.is_empty
tparams) then
173 indentEnv "tpenv" (fun () ->
174 List.iter
tparams ~f
:begin fun tparam
->
175 let lower = Typing_set.elements
(Env.get_lower_bounds env tparam
) in
176 let upper = Typing_set.elements
(Env.get_upper_bounds env tparam
) in
178 (if not
(List.is_empty
lower)
179 then (log_type_list env
lower; lprintf (Normal Green
) " <: "));
180 lprintf (Bold Green
) "%s" tparam
;
181 (if not
(List.is_empty
upper)
182 then (lprintf (Normal Green
) " <: "; log_type_list env
upper))
186 indentEnv "tvenv" (fun () ->
187 IMap.iter
begin fun var
188 Env.{ lower_bounds
; upper_bounds
;
189 appears_covariantly
; appears_contravariantly
; _
} ->
190 let lower = Typing_set.elements lower_bounds
in
191 let upper = Typing_set.elements upper_bounds
in
193 (if not
(List.is_empty
lower)
194 then (log_type_list env
lower; lprintf (Normal Green
) " <: "));
195 lprintf (Bold Green
) "%s%s#%d"
196 (if appears_covariantly
then "+" else "")
197 (if appears_contravariantly
then "-" else "")
199 (if not
(List.is_empty
upper)
200 then (lprintf (Normal Green
) " <: "; log_type_list env
upper))
204 indentEnv "tyvars_stack" (fun () ->
205 lprintf (Normal Green
) "%s"
206 (String.concat ~sep
:"/" (List.map ~f
:(fun vars
-> "{" ^
String.concat ~sep
:","
207 (List.map ~f
:(fun i
-> Printf.sprintf
"#%d" i
) vars
) ^
"}")
208 env
.Env.tyvars_stack
)))
210 let log_fake_members env
=
211 let lenv = env
.Env.lenv in
212 let fakes = lenv.Env.fake_members
in
213 indentEnv "fake_members" (fun () ->
214 (match fakes.Env.last_call
with
218 lprintf (Normal Green
) "last_call: %s" (Pos.string (Pos.to_absolute p
));
221 lprintf (Normal Green
) "invalid:";
222 SSet.iter
(lprintf (Normal Green
) " %s") fakes.Env.invalid
;
224 lprintf (Normal Green
) "valid:";
225 SSet.iter
(lprintf (Normal Green
) " %s") fakes.Env.valid
;
228 let log_position p f
=
230 match Pos.Map.get p
!iterations with
231 | None
-> iterations := Pos.Map.add p
1 !iterations; 1
232 | Some
n -> iterations := Pos.Map.add p
(n+1) !iterations; n+1 in
233 (* If we've hit this many iterations then something must have gone wrong
234 * so let's not bother spewing to the log *)
237 indentEnv (Pos.string (Pos.to_absolute p
)
238 ^
(if n = 1 then "" else "[" ^ string_of_int
n ^
"]")) f
240 let log_subtype_prop ?
(do_normalize
= false) env message prop
=
241 lprintf (Tty.Bold
Tty.Green
) "%s: " message
;
242 lprintf (Tty.Normal
Tty.Green
) "%s"
243 (Typing_print.subtype_prop ~do_normalize env prop
);
246 (* Log the environment: local_types, subst, tenv and tpenv *)
247 let hh_show_env p env
=
252 log_fake_members env
;
254 log_env_diff (!lastenv) env
;
258 log_subtype_prop env
"subtype_prop" env
.Env.subtype_prop
);
261 (* Log the type of an expression *)
262 let hh_show p env ty
=
263 let s1 = Typing_print.debug env ty
in
264 let s2_opt = Typing_print.constraints_for_type env ty
in
267 lprintf (Normal Green
) "%s" s1;
271 | Some s2
-> (lprintf (Normal Green
) "%s" s2
; lnewline ()))
274 (* Simple type of possible log data *)
276 | Log_head
of string * log_structure list
277 | Log_type
of string * Typing_defs.locl
Typing_defs.ty
279 let log_with_level env key level log_f
=
280 if Env.get_log_level env key
>= level
then log_f
()
283 let log_types p env items
=
287 List.iter items
(fun item
->
289 | Log_head
(message
, items
) ->
290 indentEnv ~color
:(Normal Yellow
) message
(fun () -> go items
)
291 | Log_type
(message
, ty
) ->
292 let s = Typing_print.debug env ty
in
293 lprintf (Bold Green
) "%s: " message
;
294 lprintf (Normal Green
) "%s" s;
298 let log_prop ?
(do_normalize
= false) level p message env prop
=
299 log_with_level env
"prop" level
(fun () ->
300 log_position p
(fun () -> log_subtype_prop ~do_normalize env message prop
))
302 let increment_feature_count env
s =
303 if GlobalOptions.tco_language_feature_logging
(Env.get_tcopt env
)
304 then Measure.sample
s 1.0