2 * Copyright (c) Facebook, Inc. and its affiliates.
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the "hack" directory of this source tree.
10 module Class
= Typing_classes_heap.Api
14 type type_key
= string
16 type gconst_key
= string
18 type module_key
= string
20 type fun_decl
= Typing_defs.fun_elt
22 type class_decl
= Typing_classes_heap.Api.t
24 type typedef_decl
= Typing_defs.typedef_type
26 type gconst_decl
= Typing_defs.const_decl
28 type module_decl
= Typing_defs.module_def_type
30 let ( let* ) = Caml.Option.bind
32 let err_not_found = Typedef_provider.err_not_found
34 let find_in_direct_decl_parse = Typedef_provider.find_in_direct_decl_parse
36 (** This cache caches the result of full class computations
37 (the class merged with all its inherited members.) *)
42 type t
= Typing_classes_heap.class_t
44 let description = "Decl_Typing_ClassType"
50 let declare_folded_class (ctx
: Provider_context.t
) (name
: type_key
) :
51 Decl_defs.decl_class_type
* Decl_store.class_members
option =
52 match Provider_context.get_backend ctx
with
53 | Provider_backend.Analysis
-> failwith
"invalid"
56 Errors.run_in_decl_mode
(fun () ->
57 Decl_folded_class.class_decl_if_missing ~sh
:SharedMem.Uses ctx name
)
59 | None
-> err_not_found None name
60 | Some decl_and_members
-> decl_and_members
)
62 let lookup_or_populate_class_cache class_name populate
=
63 match Cache.get class_name
with
64 | Some _
as result
-> result
67 match populate class_name
with
70 Cache.add class_name v
;
75 ?
(tracing_info
: Decl_counters.tracing_info
option)
76 (ctx
: Provider_context.t
)
77 (class_name
: type_key
) : class_decl
option =
78 Decl_counters.count_decl ?tracing_info
Decl_counters.Class class_name
80 (* There's a confusing matrix of possibilities:
81 SHALLOW - in this case, the Typing_classes_heap.class_t we get back is
82 just a small shim that does memoization; further accessors on it
83 like "get_method" will lazily call Linearization_provider and Shallow_classes_provider
84 to get more information
85 EAGER - in this case, the Typing_classes_heap.class_t we get back is
86 an "folded" object which keeps an intire index of all members, although
87 those members are fetched lazily via Lazy.t.
91 LOCAL BACKEND - the class_t is cached in the local backend.
92 SHAREDMEM BACKEND - the class_t is cached in the worker-local 'Cache' heap.
93 Note that in the case of eager, the class_t is really just a fairly simple
94 derivation of the decl_class_type that lives in shmem.
95 DECL BACKEND - the class_t is cached in the worker-local 'Cache' heap *)
96 match Provider_context.get_backend ctx
with
97 | Provider_backend.Analysis
->
100 lookup_or_populate_class_cache class_name
(fun class_name
->
101 Decl_store.((get
()).get_class class_name
)
102 |> Option.map ~f
:Typing_classes_heap.make_eager_class_decl
)
105 | Some v
-> Some
(counter
, v
, Some ctx
)
107 | Provider_backend.Pessimised_shared_memory _
->
108 (* No pessimisation needs to be done here directly. All pessimisation is
109 * done on the shallow classes within [Shallow_classes_provider] that the
110 * [Typing_classes_heap.Api.t] returned here is constructed from
111 * Crucially, we do not use the [Cache] here, which would contain
112 * outdated member types once we update its members during
115 match Typing_classes_heap.get ctx class_name
declare_folded_class with
117 | Some v
-> Some
(counter
, v
, Some ctx
)
119 | Provider_backend.Shared_memory
120 | Provider_backend.Decl_service _
->
123 lookup_or_populate_class_cache class_name
(fun class_name
->
124 Typing_classes_heap.get ctx class_name
declare_folded_class)
127 | Some v
-> Some
(counter
, v
, Some ctx
)
129 | Provider_backend.Local_memory
{ Provider_backend.decl_cache
; _
} ->
130 let open Option.Monad_infix
in
131 Typing_classes_heap.get_class_with_cache
136 >>| fun cls
-> (counter
, cls
, Some ctx
)
137 | Provider_backend.Rust_provider_backend backend
->
140 lookup_or_populate_class_cache class_name
(fun class_name
->
141 Rust_provider_backend.Decl.get_folded_class backend class_name
142 |> Option.map ~f
:Typing_classes_heap.make_eager_class_decl
)
145 | Some v
-> Some
(counter
, v
, Some ctx
)
148 let maybe_pessimise_fun_decl ctx fun_decl
=
149 if TypecheckerOptions.everything_sdt
(Provider_context.get_tcopt ctx
) then
154 Decl_enforceability.(
165 ?
(tracing_info
: Decl_counters.tracing_info
option)
166 (ctx
: Provider_context.t
)
167 (fun_name
: fun_key
) : fun_decl
option =
168 Option.map ~f
:(maybe_pessimise_fun_decl ctx
)
169 @@ Decl_counters.count_decl
Decl_counters.Fun ?tracing_info fun_name
171 match Provider_context.get_backend ctx
with
172 | Provider_backend.Analysis
-> Decl_store.((get
()).get_fun fun_name
)
173 | Provider_backend.Pessimised_shared_memory info
->
174 (match Decl_store.((get
()).get_fun fun_name
) with
177 (match Naming_provider.get_fun_path ctx fun_name
with
180 find_in_direct_decl_parse
185 Shallow_decl_defs.to_fun_decl_opt
188 info
.Provider_backend.pessimise_fun
193 if info
.Provider_backend.store_pessimised_result
then
194 Decl_store.((get
()).add_fun
) fun_name
ft;
197 | Provider_backend.Shared_memory
->
198 (match Decl_store.((get
()).get_fun fun_name
) with
201 (match Naming_provider.get_fun_path ctx fun_name
with
203 find_in_direct_decl_parse
208 Shallow_decl_defs.to_fun_decl_opt
210 | Provider_backend.Local_memory
{ Provider_backend.decl_cache
; _
} ->
211 Provider_backend.Decl_cache.find_or_add
213 ~key
:(Provider_backend.Decl_cache_entry.Fun_decl fun_name
)
215 match Naming_provider.get_fun_path ctx fun_name
with
217 find_in_direct_decl_parse
222 Shallow_decl_defs.to_fun_decl_opt
224 | Provider_backend.Decl_service
{ decl
; _
} ->
225 Decl_service_client.rpc_get_fun decl fun_name
226 | Provider_backend.Rust_provider_backend backend
->
227 Rust_provider_backend.Decl.get_fun backend fun_name
229 let maybe_pessimise_typedef_decl ctx typedef_decl
=
230 if TypecheckerOptions.everything_sdt
(Provider_context.get_tcopt ctx
) then
231 (* TODO: deal with super constraint *)
232 match typedef_decl
.Typing_defs.td_as_constraint
with
233 | Some _
-> typedef_decl
235 let open Typing_defs
in
236 let pos = typedef_decl
.td_pos
in
241 (Decl_enforceability.supportdyn_mixed
243 (Reason.Rwitness_from_decl
pos));
249 ?
(tracing_info
: Decl_counters.tracing_info
option)
250 (ctx
: Provider_context.t
)
251 (typedef_name
: type_key
) : typedef_decl
option =
252 Option.map ~f
:(maybe_pessimise_typedef_decl ctx
)
253 @@ Decl_counters.count_decl
Decl_counters.Typedef ?tracing_info typedef_name
255 match Provider_context.get_backend ctx
with
256 | Provider_backend.Analysis
-> Decl_store.((get
()).get_typedef typedef_name
)
257 | Provider_backend.Shared_memory
->
258 Typedef_provider.get_typedef ctx typedef_name
259 | Provider_backend.Pessimised_shared_memory info
->
260 (match Decl_store.((get
()).get_typedef typedef_name
) with
263 (match Naming_provider.get_typedef_path ctx typedef_name
with
265 let* original_typedef
=
266 find_in_direct_decl_parse
271 Shallow_decl_defs.to_typedef_decl_opt
274 info
.Provider_backend.pessimise_typedef
279 if info
.Provider_backend.store_pessimised_result
then
280 Decl_store.((get
()).add_typedef
) typedef_name
typedef;
283 | Provider_backend.Local_memory
{ Provider_backend.decl_cache
; _
} ->
284 Provider_backend.Decl_cache.find_or_add
286 ~key
:(Provider_backend.Decl_cache_entry.Typedef_decl typedef_name
)
288 match Naming_provider.get_typedef_path ctx typedef_name
with
290 find_in_direct_decl_parse
295 Shallow_decl_defs.to_typedef_decl_opt
297 | Provider_backend.Decl_service
{ decl
; _
} ->
298 Decl_service_client.rpc_get_typedef decl typedef_name
299 | Provider_backend.Rust_provider_backend backend
->
300 Rust_provider_backend.Decl.get_typedef backend typedef_name
303 ?
(tracing_info
: Decl_counters.tracing_info
option)
304 (ctx
: Provider_context.t
)
305 (gconst_name
: gconst_key
) : gconst_decl
option =
306 Decl_counters.count_decl
Decl_counters.GConst ?tracing_info gconst_name
308 match Provider_context.get_backend ctx
with
309 | Provider_backend.Analysis
-> Decl_store.((get
()).get_gconst gconst_name
)
310 | Provider_backend.Pessimised_shared_memory info
->
311 (match Decl_store.((get
()).get_gconst gconst_name
) with
314 (match Naming_provider.get_const_path ctx gconst_name
with
316 let* original_gconst
=
317 find_in_direct_decl_parse
322 Shallow_decl_defs.to_const_decl_opt
325 info
.Provider_backend.pessimise_gconst
330 (if info
.Provider_backend.store_pessimised_result
then
331 Decl_store.((get
()).add_gconst gconst_name
gconst));
334 | Provider_backend.Shared_memory
->
335 (match Decl_store.((get
()).get_gconst gconst_name
) with
338 (match Naming_provider.get_const_path ctx gconst_name
with
340 find_in_direct_decl_parse
345 Shallow_decl_defs.to_const_decl_opt
347 | Provider_backend.Local_memory
{ Provider_backend.decl_cache
; _
} ->
348 Provider_backend.Decl_cache.find_or_add
350 ~key
:(Provider_backend.Decl_cache_entry.Gconst_decl gconst_name
)
352 match Naming_provider.get_const_path ctx gconst_name
with
354 find_in_direct_decl_parse
359 Shallow_decl_defs.to_const_decl_opt
361 | Provider_backend.Decl_service
{ decl
; _
} ->
362 Decl_service_client.rpc_get_gconst decl gconst_name
363 | Provider_backend.Rust_provider_backend backend
->
364 Rust_provider_backend.Decl.get_gconst backend gconst_name
366 let prepare_for_typecheck
367 (ctx
: Provider_context.t
) (path
: Relative_path.t
) (content
: string) :
369 match Provider_context.get_backend ctx
with
370 | Provider_backend.Analysis
371 | Provider_backend.Rust_provider_backend _
372 | Provider_backend.Pessimised_shared_memory _
373 | Provider_backend.Shared_memory
374 | Provider_backend.Local_memory _
->
376 (* When using the decl service, before typechecking the file, populate our
377 decl caches with the symbols declared within that file. If we leave this to
378 the decl service, then in longer files, the decls declared later in the
379 file may be evicted by the time we attempt to typecheck them, forcing the
380 decl service to re-parse the file. This can lead to many re-parses in
382 | Provider_backend.Decl_service
{ decl
; _
} ->
383 Decl_service_client.parse_and_cache_decls_in decl path content
386 ?
(tracing_info
: Decl_counters.tracing_info
option)
387 (ctx
: Provider_context.t
)
388 (module_name
: module_key
) : module_decl
option =
389 Decl_counters.count_decl
Decl_counters.Module_decl ?tracing_info module_name
391 let fetch_from_backing_store () =
392 Naming_provider.get_module_path ctx module_name
393 |> Option.bind ~f
:(fun filename
->
394 find_in_direct_decl_parse
399 Shallow_decl_defs.to_module_decl_opt
)
401 match Provider_context.get_backend ctx
with
402 | Provider_backend.Analysis
-> Decl_store.((get
()).get_module module_name
)
403 | Provider_backend.Pessimised_shared_memory _
404 | Provider_backend.Shared_memory
->
406 Decl_store.((get
()).get_module module_name
)
407 (fetch_from_backing_store ())
408 | Provider_backend.Local_memory
{ Provider_backend.decl_cache
; _
} ->
409 Provider_backend.Decl_cache.find_or_add
411 ~key
:(Provider_backend.Decl_cache_entry.Module_decl module_name
)
412 ~default
:fetch_from_backing_store
413 | Provider_backend.Decl_service
{ decl
; _
} ->
414 Decl_service_client.rpc_get_module decl module_name
415 | Provider_backend.Rust_provider_backend backend
->
416 Rust_provider_backend.Decl.get_module backend module_name
418 let get_overridden_method ctx ~class_name ~method_name ~is_static
:
419 Typing_defs.class_elt
option =
420 let open Option.Monad_infix
in
421 get_class ctx class_name
>>= fun cls
->
422 Class.overridden_method cls ~method_name ~is_static ~
get_class
424 let local_changes_push_sharedmem_stack () =
425 Decl_store.((get
()).push_local_changes
())
427 let local_changes_pop_sharedmem_stack () =
428 Decl_store.((get
()).pop_local_changes
())
430 let declare_folded_class_in_file_FOR_TESTS_ONLY ctx cid
=
431 fst
(declare_folded_class ctx cid
)