2 * Copyright (c) 2015, 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 (*****************************************************************************)
12 (* Pretty printing of types *)
13 (*****************************************************************************)
20 module SN
= Naming_special_names
21 module Reason
= Typing_reason
22 module TySet
= Typing_set
23 module Cls
= Decl_provider.Class
25 let shallow_decl_enabled () =
26 TypecheckerOptions.shallow_class_decl
(GlobalNamingOptions.get
())
28 (*****************************************************************************)
29 (* Module used to "suggest" types.
30 * When a type is missing, it is nice to suggest a type to the user.
31 * However, there are some cases where parts of the type is still unresolved.
32 * When that is the case, we print '...' and let the user replace the missing
33 * parts with a real type. So if we inferred that something was a Vector,
34 * but we didn't manage to infer the type of the elements, the output becomes:
37 (*****************************************************************************)
39 module Suggest
= struct
41 let rec type_: type a
. a ty
-> string = fun (_
, ty
) ->
44 | Tdarray _
-> "darray"
45 | Tvarray _
-> "varray"
46 | Tvarray_or_darray _
-> "varray_or_darray"
47 | Tarraykind AKdarray
(_
, _
)
49 | Tarraykind AKvarray _
-> "varray"
50 | Tarraykind _
-> "array"
51 | Tdynamic
-> "dynamic"
52 | Tthis
-> SN.Typehints.this
54 | Ttuple
(l
) -> "("^list l^
")"
58 | Tnonnull
-> "nonnull"
59 | Tnothing
-> "nothing"
61 | Tabstract
(AKgeneric s
, _
) -> s
62 | Toption
(_
, Tnonnull
) -> "mixed"
63 | Toption ty
-> "?" ^
type_ ty
64 | Tlike ty
-> "~" ^
type_ ty
69 | Tapply
((_
, cid
), []) -> Utils.strip_ns cid
70 | Tapply
((_
, cid
), [x
]) -> (Utils.strip_ns cid
)^
"<"^
type_ x^
">"
71 | Tapply
((_
, cid
), l
) -> (Utils.strip_ns cid
)^
"<"^list l^
">"
72 | Tclass
((_
, cid
), _
, []) -> Utils.strip_ns cid
73 | Tabstract
((AKnewtype
(cid
, []) | AKenum cid
), _
) -> Utils.strip_ns cid
74 | Tclass
((_
, cid
), _
, [x
]) -> (Utils.strip_ns cid
)^
"<"^
type_ x^
">"
75 | Tabstract
(AKnewtype
(cid
, [x
]), _
) ->
76 (Utils.strip_ns cid
)^
"<"^
type_ x^
">"
77 | Tclass
((_
, cid
), _
, l
) -> (Utils.strip_ns cid
)^
"<"^list l^
">"
78 | Tabstract
(AKnewtype
(cid
, l
), _
) ->
79 (Utils.strip_ns cid
)^
"<"^list l^
">"
80 | Tabstract
(AKdependent
(_
, _
), _
) -> "..."
83 | Taccess
(root_ty
, ids
) ->
85 match snd root_ty
with
86 | Tapply
((_
, x), _
) -> Some
x
87 | Tthis
-> Some
SN.Typehints.this
93 ~f
:(fun acc
(_
, sid
) -> acc^
"::"^sid
)
97 and list
: type a
. a ty list
-> string = function
100 | x :: rl
-> type_ x ^
", "^ list rl
103 | Nast.Tnull
-> "null"
104 | Nast.Tvoid
-> "void"
106 | Nast.Tbool
-> "bool"
107 | Nast.Tfloat
-> "float"
108 | Nast.Tstring
-> "string"
109 | Nast.Tnum
-> "num (int/float)"
110 | Nast.Tresource
-> "resource"
111 | Nast.Tarraykey
-> "arraykey (int/string)"
112 | Nast.Tnoreturn
-> "noreturn"
116 (*****************************************************************************)
117 (* Pretty-printer of the "full" type. *)
118 (* This is used in server/symbolTypeService and elsewhere *)
119 (* With debug_mode set it is used for hh_show_env *)
120 (*****************************************************************************)
123 module Env
= Typing_env
127 let format_env = Format_env.{default
with line_width
= 60}
129 let text_strip_ns s
= Doc.text
(Utils.strip_ns s
)
131 let (^^
) a b
= Concat
[a
; b
]
133 let debug_mode = ref false
134 let show_verbose env
= Env.get_log_level env
"show" > 1
135 let blank_tyvars = ref false
136 let comma_sep = Concat
[text
","; Space
]
140 let list_sep ?
(split
=true) (s
: Doc.t
) (f
: 'a
-> Doc.t
) (l
: 'a list
) : Doc.t
=
141 let split = if split then Split
else Nothing
in
142 let max_idx = List.length l
- 1 in
143 let elements = List.mapi l ~f
:begin fun idx element
->
146 else Concat
[f element
; s
; split]
150 | xs
-> Nest
[split; Concat xs
; split]
152 let delimited_list sep left_delimiter f l right_delimiter
=
155 WithRule
(Rule.Parental
, Concat
[
157 text right_delimiter
;
161 let list: type c
. _
-> (c
-> Doc.t
) -> c
list -> _
-> _
=
162 fun ld
x y rd
-> delimited_list comma_sep ld
x y rd
164 let shape_map fdm f_field
=
165 let compare = (fun (k1
, _
) (k2
, _
) ->
166 compare (Env.get_shape_field_name k1
) (Env.get_shape_field_name k2
)) in
167 let fields = List.sort ~
compare (Nast.ShapeMap.elements fdm
) in
168 List.map
fields f_field
170 let rec ty: type a
. _
-> _
-> _
-> a
ty -> Doc.t
=
171 fun to_doc st env
(r
, x) ->
172 let d = ty_ to_doc st env
x in
174 | Typing_reason.Rsolve_fail _
-> Concat
[text
"{suggest:"; d; text
"}"]
177 and ty_
: type a
. _
-> _
-> _
-> a ty_
-> Doc.t
=
178 fun to_doc st env
x ->
179 let k: type b
. b
ty -> _
= fun x -> ty to_doc st env
x in
182 | Terr
-> text
(if !debug_mode then "err" else "_")
183 | Tthis
-> text
SN.Typehints.this
184 | Tmixed
-> text
"mixed"
185 | Tdynamic
-> text
"dynamic"
186 | Tnonnull
-> text
"nonnull"
187 | Tnothing
-> text
"nothing"
188 | Tdarray
(x, y
) -> list "darray<" k [x; y
] ">"
189 | Tvarray
x -> list "varray<" k [x] ">"
190 | Tvarray_or_darray
x -> list "varray_or_darray<" k [x] ">"
191 | Tarraykind
(AKvarray_or_darray
x) -> list "varray_or_darray<" k [x] ">"
192 | Tarraykind AKany
-> text
"array"
193 | Tarraykind AKempty
-> text
"array (empty)"
194 | Tarray
(None
, None
) -> text
"array"
195 | Tarraykind AKvarray
x -> list "varray<" k [x] ">"
196 | Tarraykind
(AKvec
x) -> list "array<" k [x] ">"
197 | Tarray
(Some
x, None
) -> list "array<" k [x] ">"
198 | Tarray
(Some
x, Some y
) -> list "array<" k [x; y
] ">"
199 | Tarraykind AKdarray
(x, y
) -> list "darray<" k [x; y
] ">"
200 | Tarraykind
(AKmap
(x, y
)) -> list "array<" k [x; y
] ">"
201 | Tarray
(None
, Some _
) -> assert false
202 | Tclass
((_
, s
), Exact
, []) when !debug_mode ->
203 Concat
[text
"exact"; Space
; to_doc s
]
204 | Tclass
((_
, s
), _
, []) -> to_doc s
205 | Tapply
((_
, s
), []) -> to_doc s
206 | Tgeneric s
-> to_doc s
207 | Taccess
(root_ty
, ids
) -> Concat
[
209 to_doc
(List.fold_left ids
210 ~f
:(fun acc
(_
, sid
) -> acc ^
"::" ^ sid
) ~init
:"")
212 | Toption
(_
, Tnonnull
) -> text
"mixed"
213 | Toption
(r
, Tunion tyl
)
214 when TypecheckerOptions.like_types
(Env.get_tcopt env
) &&
215 List.exists ~f
:(fun (_
, ty) -> ty = Tdynamic
) tyl
->
216 (* Unions with null become Toption, which leads to the awkward ?~...
217 * The Tunion case can better handle this *)
218 k (r
, Tunion
((r
, Tprim
Nast.Tnull
) :: tyl
))
219 | Toption
x -> Concat
[text
"?"; k x]
220 | Tlike
x -> Concat
[text
"~"; k x]
221 | Tprim
x -> text
@@ prim
x
223 let _, n'
= Env.get_var env n
in
224 let _, ety
= Env.expand_type env
(Reason.Rnone
, x) in
226 (* For unsolved type variables, always show the type variable *)
230 else if !blank_tyvars
231 then text
"[unresolved]"
232 else text
("#" ^ string_of_int n
)
235 if ISet.mem n' st
then text
"[rec]"
237 (* For hh_show_env we further show the type variable number *)
238 if show_verbose env
then (text
("#" ^
(string_of_int n
)))
240 let st = ISet.add n'
st in
241 Concat
[prepend; ty to_doc
st env ety
]
243 | Tfun ft
-> Concat
[
244 if ft
.ft_abstract
then text
"abs" ^^ Space
else Nothing
;
246 if ft
.ft_is_coroutine
then text
"coroutine" ^^ Space
else Nothing
;
248 fun_type to_doc
st env ft
;
250 (match ft
.ft_ret
with
251 | (Reason.Rdynamic_yield
_, _) -> Space ^^ text
"[DynamicYield]"
254 | Tclass
((_, s
), exact
, tyl
) ->
255 let d = to_doc s ^^
list "<" k tyl
">" in
256 begin match exact
with
257 | Exact
when !debug_mode -> Concat
[text
"exact"; Space
; d]
260 | Tabstract
(AKnewtype
(s
, []), _) -> to_doc s
261 | Tabstract
(AKnewtype
(s
, tyl
), _) -> to_doc s ^^
list "<" k tyl
">"
262 | Tabstract
(ak
, cstr
) ->
263 let cstr_info = if !debug_mode then
266 | Some
ty -> Concat
[Space
; text
"as"; Space
; k ty]
268 Concat
[to_doc
@@ AbstractKind.to_string ak
; cstr_info]
269 (* Don't strip_ns here! We want the FULL type, including the initial slash.
271 | Tapply
((_, s
), tyl
) -> to_doc s ^^
list "<" k tyl
">"
272 | Ttuple tyl
-> list "(" k tyl
")"
274 begin match Env.get_anonymous env
id with
275 | Some
(Reactive
_, true, _, _, _) -> text
"[coroutine rx fun]"
276 | Some
(Nonreactive
, true, _, _, _) -> text
"[coroutine fun]"
277 | Some
(Reactive
_, false, _, _, _) -> text
"[rx fun]"
281 if TypecheckerOptions.new_inference
(Env.get_tcopt env
)
283 else text
"[unresolved]"
284 | Tunion tyl
when TypecheckerOptions.like_types
(Env.get_tcopt env
) ->
285 let tyl = List.fold_right
tyl ~init
:Typing_set.empty
286 ~f
:Typing_set.add
|> Typing_set.elements in
287 let dynamic, null
, nonnull
= List.partition3_map
tyl ~f
:(fun t
->
289 | _, Tdynamic
-> `Fst t
290 | _, Tprim
Nast.Tnull
-> `Snd t
293 begin match dynamic, null
, nonnull
with
294 (* type isn't nullable or dynamic *)
296 if show_verbose env
then Concat
[text
"("; k ty; text
")"] else k ty
298 delimited_list (Space ^^ text
"|" ^^ Space
) "(" k nonnull
")"
299 (* Type only is null *)
301 if show_verbose env
then text
"(null)" else text
"null"
302 (* Type only is dynamic *)
304 if show_verbose env
then text
"(dynamic)" else text
"dynamic"
305 (* Type is nullable single type *)
308 then Concat
[text
"(null |"; k ty; text
")"]
309 else Concat
[text
"?"; k ty]
310 (* Type is like single type *)
313 then Concat
[text
"(dynamic |"; k ty; text
")"]
314 else Concat
[text
"~"; k ty]
315 (* Type is like nullable single type *)
318 then Concat
[text
"(dynamic | null |"; k ty; text
")"]
319 else Concat
[text
"~?"; k ty]
324 delimited_list (Space ^^ text
"|" ^^ Space
) "(" k nonnull
")"
328 let tyl = List.fold_right
tyl ~init
:Typing_set.empty
329 ~f
:Typing_set.add
|> Typing_set.elements in
330 let null, nonnull
= List.partition_tf
tyl ~f
:(fun (_, t
) -> t
= Tprim
Nast.Tnull
) in
331 begin match null, nonnull
with
332 (* type isn't nullable *)
334 if show_verbose env
then Concat
[text
"("; k ty; text
")"] else k ty
336 delimited_list (Space ^^ text
"|" ^^ Space
) "(" k nonnull
")"
337 (* Type only is null *)
339 if show_verbose env
then text
"(null)" else text
"null"
340 (* Type is nullable single type *)
343 then Concat
[text
"(null |"; k ty; text
")"]
344 else Concat
[text
"?"; k ty]
345 (* Type is nullable unresolved type *)
349 delimited_list (Space ^^ text
"|" ^^ Space
) "(" k nonnull
")"
352 | Tobject
-> text
"object"
353 | Tshape
(fields_known
, fdm
) ->
355 let f_field (shape_map_key
, { sft_optional
; sft_ty
}) =
357 match shape_map_key
with Ast.SFlit_str
_ -> text
"'" | _ -> Nothing
360 if sft_optional
then text
"?" else Nothing
;
362 to_doc
(Env.get_shape_field_name shape_map_key
);
370 shape_map fdm
f_field
373 match fields_known
with
374 | FieldsFullyKnown
-> fields
375 | FieldsPartiallyKnown
_ -> fields @ [text
"..."]
378 list "shape(" id fields ")";
379 match fields_known
with
380 | FieldsFullyKnown
-> Nothing
381 | FieldsPartiallyKnown unset_fields
->
382 match Nast.ShapeMap.elements unset_fields
with
385 text
"(unset fields:";
387 Concat
(List.map
(Nast.ShapeMap.ordered_keys unset_fields
) begin fun k ->
388 Concat
[to_doc
(Env.get_shape_field_name
k); Space
]
396 | Nast.Tnull
-> "null"
397 | Nast.Tvoid
-> "void"
399 | Nast.Tbool
-> "bool"
400 | Nast.Tfloat
-> "float"
401 | Nast.Tstring
-> "string"
403 | Nast.Tresource
-> "resource"
404 | Nast.Tarraykey
-> "arraykey"
405 | Nast.Tnoreturn
-> "noreturn"
407 and fun_type
: type a
. _ -> _ -> _ -> a fun_type
-> _ =
408 fun to_doc
st env ft
->
409 let params = List.map ft
.ft_params
(fun_param to_doc
st env
) in
411 match ft
.ft_arity
with
412 | Fstandard
_ -> None
413 | Fellipsis
_ -> Some
(text
"...")
414 | Fvariadic
(_, p
) ->
416 (match p
.fp_type
with
418 | _ -> fun_param to_doc
st env p
424 match variadic_param with
426 | Some
variadic_param -> params @ [variadic_param]
429 (* only print tparams when they have been instantiated with targs
430 * so that they correctly express reified parameterization *)
431 (match ft
.ft_tparams
with
433 | _, FTKtparams
-> Nothing
434 | l
, FTKinstantiated_targs
-> list "<" (tparam to_doc
st env
) l
">"
436 list "(" id params "):";
438 ty to_doc
st env ft
.ft_ret
441 and fun_param
: type a
. _ -> _ -> _ -> a fun_param
-> _ =
442 fun to_doc
st env
{ fp_name
; fp_type
; fp_kind
; _ } ->
445 | FPinout
-> text
"inout" ^^ Space
448 match fp_name
, fp_type
with
449 | None
, _ -> ty to_doc
st env fp_type
450 | Some param_name
, (_, Tany
) -> text param_name
451 | Some param_name
, _ ->
452 Concat
[ty to_doc
st env fp_type
; Space
; text param_name
]
455 and tparam
: type a
. _ -> _ -> _ -> a
Typing_defs.tparam
-> _ =
456 fun to_doc
st env
{ tp_name
= (_, x); tp_constraints
= cstrl
; tp_reified
= r
; _ } ->
459 | Nast.Erased
-> Nothing
460 | Nast.SoftReified
-> text
"<<__Soft>> reify" ^^ Space
461 | Nast.Reified
-> text
"reify" ^^ Space
end;
463 list_sep ~
split:false Space
(tparam_constraint to_doc
st env
) cstrl
;
466 and tparam_constraint
:
467 type a
. _ -> _ -> _ -> (Ast.constraint_kind
* a
ty) -> _ =
468 fun to_doc
st env
(ck
, cty
) ->
473 | Ast.Constraint_as
-> "as"
474 | Ast.Constraint_super
-> "super"
475 | Ast.Constraint_eq
-> "="
476 | Ast.Constraint_pu_from
-> "from"
482 (* For a given type parameter, construct a list of its constraints *)
483 let get_constraints_on_tparam env tparam
=
484 let lower = Env.get_lower_bounds env tparam
in
485 let upper = Env.get_upper_bounds env tparam
in
486 let equ = Env.get_equal_bounds env tparam
in
487 (* If we have an equality we can ignore the other bounds *)
488 if not
(TySet.is_empty
equ)
489 then List.map
(TySet.elements equ) (fun ty -> (tparam
, Ast.Constraint_eq
, ty))
491 List.map
(TySet.elements lower) (fun ty -> (tparam
, Ast.Constraint_super
, ty))
493 List.map
(TySet.elements upper) (fun ty -> (tparam
, Ast.Constraint_as
, ty))
495 let to_string to_doc env
x =
496 ty to_doc
ISet.empty env
x
497 |> Libhackfmt.format_doc_unbroken
format_env
500 let constraints_for_type to_doc env
ty =
501 let tparams = SSet.elements (Env.get_tparams env
ty) in
502 let constraints = List.concat_map
tparams (get_constraints_on_tparam env
) in
503 if List.is_empty
constraints
509 WithRule
(Rule.Parental
,
510 list_sep comma_sep begin fun (tparam
, ck
, ty) ->
511 Concat
[text tparam
; tparam_constraint to_doc
ISet.empty env
(ck
, ty)]
516 let to_string_rec env n
x =
517 ty Doc.text
(ISet.add n
ISet.empty
) env
x
518 |> Libhackfmt.format_doc_unbroken
format_env
521 let to_string_strip_ns env
x =
522 to_string text_strip_ns env
x
524 let to_string_decl tcopt
(x: decl
ty) =
526 Typing_env.empty tcopt
Relative_path.default
528 to_string Doc.text
env x
530 let to_string_with_identity env x occurrence definition_opt
=
532 let open SymbolDefinition
in
533 let print_mod m
= text
(string_of_modifier m
) ^^ Space
in
534 match definition_opt
with
537 begin match def
.modifiers
with
539 (* It looks weird if we line break after a single modifier. *)
541 | ms
-> Concat
(List.map ms
print_mod) ^^ SplitWith
Cost.Base
545 let open SymbolOccurrence
in
546 match occurrence
, x with
547 | { type_ = Class
; name
; _ }, _ -> Concat
[text
"class"; Space
; text_strip_ns name
]
549 | { type_ = Function
; name
; _ }, (_, Tfun ft
)
550 | { type_ = Method
(_, name
); _ }, (_, Tfun ft
) ->
551 (* Use short names for function types since they display a lot more
552 information to the user. *)
557 fun_type
text_strip_ns ISet.empty
env ft
;
560 | { type_ = Property
_; name
; _ }, _
561 | { type_ = ClassConst
_; name
; _ }, _
562 | { type_ = GConst
; name
; _ }, _ ->
564 ty text_strip_ns ISet.empty
env x;
569 | _ -> ty text_strip_ns ISet.empty
env x
572 constraints_for_type text_strip_ns env x
573 |> Option.value_map ~default
:Nothing ~f
:(fun x -> Concat
[Newline
; x])
575 Concat
[prefix; body; constraints]
576 |> Libhackfmt.format_doc
format_env
581 let with_blank_tyvars f
=
582 Full.blank_tyvars := true;
584 Full.blank_tyvars := false;
587 (*****************************************************************************)
588 (* Computes the string representing a type in an error message.
590 (*****************************************************************************)
592 module ErrorString
= struct
594 module Env
= Typing_env
596 | Nast.Tnull
-> "null"
597 | Nast.Tvoid
-> "void"
598 | Nast.Tint
-> "an int"
599 | Nast.Tbool
-> "a bool"
600 | Nast.Tfloat
-> "a float"
601 | Nast.Tstring
-> "a string"
602 | Nast.Tnum
-> "a num (int | float)"
603 | Nast.Tresource
-> "a resource"
604 | Nast.Tarraykey
-> "an array key (int | string)"
605 | Nast.Tnoreturn
-> "noreturn (throws or exits)"
607 let varray = "a varray"
608 let darray = "a darray"
609 let varray_or_darray = "a varray_or_darray"
611 let rec type_: _ -> locl ty_
-> _ = function env -> function
612 | Tany
-> "an untyped value"
613 | Terr
-> "a type error"
614 | Tdynamic
-> "a dynamic value"
615 | Tunion l
-> unresolved
env l
616 | Tarraykind
(AKvarray_or_darray
_) -> varray_or_darray
617 | Tarraykind AKempty
-> "an empty array"
618 | Tarraykind AKany
-> array
(None
, None
)
619 | Tarraykind AKvarray
_
621 | Tarraykind
(AKvec
x)
622 -> array
(Some
x, None
)
623 | Tarraykind AKdarray
(_, _)
625 | Tarraykind
(AKmap
(x, y
))
626 -> array
(Some
x, Some y
)
627 | Ttuple l
-> "a tuple of size " ^ string_of_int
(List.length l
)
628 | Tnonnull
-> "a nonnull value"
629 | Toption
(_, Tnonnull
) -> "a mixed value"
630 | Toption
_ -> "a nullable type"
631 | Tprim tp
-> tprim tp
632 | Tvar
_ -> "some value"
633 | Tanon
_ -> "a function"
634 | Tfun
_ -> "a function"
635 | Tabstract
(AKnewtype
(x, _), _)
636 when x = SN.Classes.cClassname
-> "a classname string"
637 | Tabstract
(AKnewtype
(x, _), _)
638 when x = SN.Classes.cTypename
-> "a typename string"
639 | Tabstract
(ak
, cstr
) -> abstract
env ak cstr
640 | Tclass
((_, x), Exact
, tyl) ->
641 "an object of exactly the class " ^ strip_ns
x ^ inst
env tyl
642 | Tclass
((_, x), Nonexact
, tyl) ->
643 "an object of type " ^ strip_ns
x ^ inst
env tyl
644 | Tobject
-> "an object"
645 | Tshape
_ -> "a shape"
647 and array
: type a
. a
ty option * a
ty option -> _ = function
648 | None
, None
-> "an untyped array"
649 | Some
_, None
-> "an array (used like a vector)"
650 | Some
_, Some
_ -> "an array (used like a hashtable)"
654 if List.is_empty
tyl then ""
656 with_blank_tyvars (fun () ->
658 ^
String.concat ~sep
:", " (List.map
tyl ~f
:(Full.to_string_strip_ns env))
661 and abstract
env ak cstr
=
662 let x = strip_ns
@@ AbstractKind.to_string ak
in
664 | AKnewtype
(_, tyl), _ -> "an object of type " ^
x ^ inst
env tyl
665 | AKenum
_, _ -> "a value of "^
x
666 | AKgeneric s
, _ when AbstractKind.is_generic_dep_ty s
->
667 "the expression dependent type "^s
668 | AKgeneric
_, _ -> "a value of generic type "^
x
669 | AKdependent
(`cls c
, []), Some
ty ->
670 to_string env ty^
" (known to be exactly the class '"^strip_ns c^
"')"
671 | AKdependent
((`this
| `expr
_), _), _ ->
672 "the expression dependent type "^
x
673 | AKdependent
(_, _::_), _ -> "the abstract type constant "^
x
674 | AKdependent
_, _ ->
676 ^
Option.value_map cstr ~default
:""
677 ~f
:(fun ty -> "\n that is compatible with " ^
to_string env ty)
679 and unresolved
env l
=
680 let null, nonnull
= List.partition_tf l
(fun ty -> snd
ty = Tprim
Nast.Tnull
) in
681 let l = List.map nonnull
(to_string env) in
682 let s = List.fold_right
l ~f
:SSet.add ~init
:SSet.empty
in
683 let l = SSet.elements s in
689 and unresolved_
= function
690 | [] -> "an undefined value"
692 | x :: rl
-> x^
" or "^unresolved_ rl
694 and class_kind c_kind final
=
695 let fs = if final
then " final" else "" in
697 | Ast.Cabstract
-> "an abstract" ^
fs ^
" class"
698 | Ast.Cnormal
-> "a" ^
fs ^
" class"
699 | Ast.Cinterface
-> "an interface"
700 | Ast.Ctrait
-> "a trait"
701 | Ast.Cenum
-> "an enum"
702 | Ast.Crecord
-> "a record"
704 and to_string : _ -> locl
ty -> _ = fun env ty ->
705 let _, ety
= Env.expand_type
env ty in
715 | Nast.Tnull
-> "null"
716 | Nast.Tvoid
-> "void"
718 | Nast.Tbool
-> "bool"
719 | Nast.Tfloat
-> "float"
720 | Nast.Tstring
-> "string"
722 | Nast.Tresource
-> "resource"
723 | Nast.Tarraykey
-> "arraykey"
724 | Nast.Tnoreturn
-> "noreturn"
726 let param_mode_to_string = function
727 | FPnormal
-> "normal"
731 let string_to_param_mode = function
732 | "normal" -> Some FPnormal
733 | "ref" -> Some FPref
734 | "inout" -> Some FPinout
737 let rec from_type: type a
. Typing_env.env -> a
ty -> json
=
738 function env -> function ty ->
739 (* Helpers to construct fields that appear in JSON rendering of type *)
740 let kind k = ["kind", JSON_String
k] in
741 let args tys
= ["args", JSON_Array
(List.map tys
(from_type env))] in
742 let typ ty = ["type", from_type env ty] in
743 let result ty = ["result", from_type env ty] in
744 let obj x = JSON_Object
x in
745 let name x = ["name", JSON_String
x] in
746 let optional x = ["optional", JSON_Bool
x] in
747 let is_array x = ["is_array", JSON_Bool
x] in
748 let empty x = ["empty", JSON_Bool
x] in
749 let make_field (k, v
) =
750 let shape_field_name_to_json shape_field
=
751 (* TODO: need to update userland tooling? *)
752 match shape_field
with
753 | Ast.SFlit_int
(_, s) -> Hh_json.JSON_Number
s
754 | Ast.SFlit_str
(_, s) -> Hh_json.JSON_String
s
755 | Ast.SFclass_const
((_, s1
), (_, s2
)) ->
757 Hh_json.JSON_String s1
;
758 Hh_json.JSON_String s2
;
762 ["name", (shape_field_name_to_json k)] @
763 optional v
.sft_optional
@
766 ["fields", JSON_Array
(List.map fl
make_field)] in
768 ["path", JSON_Array
(List.map ids
(fun id -> JSON_String
id))] in
772 | Some
ty -> ["as", from_type env ty] in
775 let _, ty = Typing_env.expand_type
env ty in
776 begin match snd
ty with
777 | Tvar
_ -> obj @@ kind "var"
778 | _ -> from_type env ty
780 | Tarray
(opt_ty1
, opt_ty2
) ->
781 obj @@ kind "array" @ args (Option.to_list opt_ty1
@ Option.to_list opt_ty2
)
785 obj @@ kind "tuple" @ is_array false @ args tys
791 obj @@ kind "nonnull"
793 obj @@ kind "dynamic"
795 obj @@ kind "nothing"
797 obj @@ kind "generic" @ is_array false @ name s
798 | Tabstract
(AKgeneric
s, opt_ty
) ->
799 obj @@ kind "generic" @ is_array true @ name s @ as_type opt_ty
800 | Tabstract
(AKenum
s, opt_ty
) ->
801 obj @@ kind "enum" @ name s @ as_type opt_ty
802 | Tabstract
(AKnewtype
(s, tys
), opt_ty
) ->
803 obj @@ kind "newtype" @ name s @ args tys
@ as_type opt_ty
804 | Tabstract
(AKdependent
(`cls c
, ids
), opt_ty
) ->
805 obj @@ kind "path" @ ["type", obj @@ kind "class" @ name c
@ args []]
806 @ path ids
@ as_type opt_ty
807 | Tabstract
(AKdependent
(`expr
_, ids
), opt_ty
) ->
808 obj @@ kind "path" @ ["type", obj @@ kind "expr"]
809 @ path ids
@ as_type opt_ty
810 | Tabstract
(AKdependent
(`this
, ids
), opt_ty
) ->
811 obj @@ kind "path" @ ["type", obj @@ kind "this"]
812 @ path ids
@ as_type opt_ty
813 | Toption
(_, Tnonnull
) ->
816 obj @@ kind "nullable" @ args [ty]
818 obj @@ kind "like" @ args [ty]
820 obj @@ kind "primitive" @ name (prim tp
)
821 | Tapply
((_, cid
), tys
) ->
822 obj @@ kind "class" @ name cid
@ args tys
823 | Tclass
((_, cid
), _, tys
) ->
824 obj @@ kind "class" @ name cid
@ args tys
827 | Tshape
(fields_known
, fl
) ->
829 match fields_known with
830 | FieldsFullyKnown
-> true
831 | FieldsPartiallyKnown
_ ->
832 (* TODO: maybe don't drop the partially-known fields? *)
838 ["fields_known", JSON_Bool
fields_known] @
839 fields (Nast.ShapeMap.elements fl
)
841 if TypecheckerOptions.new_inference
(Typing_env.get_tcopt
env)
842 then obj @@ kind "nothing"
843 else obj @@ kind "union" @ args []
847 obj @@ kind "union" @ args tyl
848 | Taccess
(ty, ids
) ->
849 obj @@ kind "path" @ typ ty @ path (List.map ids snd
)
852 if ft
.ft_is_coroutine
853 then kind "coroutine"
854 else kind "function" in
855 let callconv cc
= ["callConvention", JSON_String
(param_mode_to_string cc
)] in
856 let param fp
= obj @@ callconv fp
.fp_kind
@ typ fp
.fp_type
in
857 let params fps
= ["params", JSON_Array
(List.map fps
param)] in
858 obj @@ fun_kind @ params ft
.ft_params
@ result ft
.ft_ret
861 | Tdarray
(ty1
, ty2
) ->
862 obj @@ kind "darray" @ args [ty1
; ty2
]
864 obj @@ kind "varray" @ args [ty]
865 | Tvarray_or_darray
ty ->
866 obj @@ kind "varray_or_darray" @ args [ty]
867 | Tarraykind
(AKvarray_or_darray
ty) ->
868 obj @@ kind "varray_or_darray" @ args [ty]
869 | Tarraykind AKany
->
870 obj @@ kind "array" @ empty false @ args []
871 | Tarraykind
(AKdarray
(ty1
, ty2
)) ->
872 obj @@ kind "darray" @ args [ty1
; ty2
]
873 | Tarraykind
(AKvarray
ty) ->
874 obj @@ kind "varray" @ args [ty]
875 | Tarraykind
(AKvec
ty) ->
876 obj @@ kind "array" @ empty false @ args [ty]
877 | Tarraykind
(AKmap
(ty1
, ty2
)) ->
878 obj @@ kind "array" @ empty false @ args [ty1
; ty2
]
879 | Tarraykind AKempty
->
880 obj @@ kind "array" @ empty true @ args []
882 type 'a deserialized_result
= ('a
ty, deserialization_error
) result
884 let wrap_json_accessor f
= fun x ->
886 | Ok
value -> Ok
value
887 | Error access_failure
->
888 Error
(Deserialization_error
889 (Hh_json.Access.access_failure_to_string access_failure
))
891 let get_string x = wrap_json_accessor (Hh_json.Access.get_string x)
892 let get_bool x = wrap_json_accessor (Hh_json.Access.get_bool x)
893 let get_array x = wrap_json_accessor (Hh_json.Access.get_array x)
894 let get_val x = wrap_json_accessor (Hh_json.Access.get_val x)
895 let get_obj x = wrap_json_accessor (Hh_json.Access.get_obj x)
896 let deserialization_error ~message ~keytrace
=
897 Error
(Deserialization_error
898 (message ^
(Hh_json.Access.keytrace_to_string keytrace
)))
899 let not_supported ~message ~keytrace
=
901 (message ^
(Hh_json.Access.keytrace_to_string keytrace
)))
902 let wrong_phase ~message ~keytrace
=
904 (message ^
(Hh_json.Access.keytrace_to_string keytrace
)))
909 : locl deserialized_result
=
910 let reason = Reason.none
in
911 let ty (ty: locl ty_
): locl deserialized_result
=
917 ~
(keytrace
: Hh_json.Access.keytrace
)
918 : locl deserialized_result
=
919 let open Result.Monad_infix
in
920 get_string "kind" (json
, keytrace
) >>= fun (kind, kind_keytrace
) ->
924 ~message
:"Cannot deserialize 'this' type."
930 ty (Toption
(reason, Tnonnull
))
937 get_string "name" (json
, keytrace
) >>= fun (name, _name_keytrace
) ->
938 get_bool "is_array" (json
, keytrace
)
939 >>= fun (is_array, _is_array_keytrace
) ->
942 aux_as json ~keytrace
>>= fun as_opt
->
943 ty (Tabstract
((AKgeneric
name), as_opt
))
946 ~message
:"Tgeneric is a decl-phase type."
950 get_string "name" (json
, keytrace
) >>= fun (name, _name_keytrace
) ->
951 aux_as json ~keytrace
>>= fun as_opt
->
952 ty (Tabstract
(AKenum
name, as_opt
))
955 get_string "name" (json
, keytrace
) >>= fun (name, name_keytrace
) ->
956 begin match Decl_provider.get_typedef
name with
958 (* We end up only needing the name of the typedef. *)
961 if name = "HackSuggest"
964 ~message
:"HackSuggest types for lambdas are not supported"
967 deserialization_error
968 ~message
:("Unknown newtype: " ^
name)
969 ~keytrace
:name_keytrace
970 end >>= fun typedef_name
->
972 get_array "args" (json
, keytrace
) >>= fun (args, args_keytrace
) ->
973 aux_args
args ~keytrace
:args_keytrace
>>= fun args ->
974 aux_as json ~keytrace
>>= fun as_opt
->
975 ty (Tabstract
(AKnewtype
(typedef_name
, args), as_opt
))
978 get_obj "type" (json
, keytrace
) >>= fun (type_json
, type_keytrace
) ->
979 get_string "kind" (type_json
, type_keytrace
) >>=
980 fun (path_kind
, path_kind_keytrace
) ->
982 get_array "path" (json
, keytrace
) >>= fun (ids_array
, ids_keytrace
) ->
985 ~keytrace
:ids_keytrace
986 ~f
:(fun id_str ~keytrace
->
991 deserialization_error
992 ~message
:"Expected a string"
997 begin match path_kind
with
999 get_string "name" (type_json
, type_keytrace
)
1000 >>= fun (class_name
, _class_name_keytrace
) ->
1001 aux_as json ~keytrace
>>= fun as_opt
->
1002 ty (Tabstract
(AKdependent
(`cls class_name
, ids), as_opt
))
1006 ~message
:"Cannot deserialize path-dependent type involving an expression"
1010 aux_as json ~keytrace
>>= fun as_opt
->
1011 ty (Tabstract
(AKdependent
(`this
, ids), as_opt
))
1014 deserialization_error
1015 ~message
:("Unknown path kind: " ^ path_kind
)
1016 ~keytrace
:path_kind_keytrace
1020 get_array "args" (json
, keytrace
) >>= fun (args, keytrace
) ->
1021 begin match args with
1023 aux ty1 ~keytrace
:("0" :: keytrace
) >>= fun ty1
->
1024 aux ty2 ~keytrace
:("1" :: keytrace
) >>= fun ty2
->
1025 ty (Tarraykind
(AKdarray
(ty1
, ty2
)))
1028 deserialization_error
1029 ~message
:(Printf.sprintf
1030 "Invalid number of type arguments to darray (expected 2): %d"
1036 get_array "args" (json
, keytrace
) >>= fun (args, keytrace
) ->
1037 begin match args with
1039 aux ty1 ~keytrace
:("0" :: keytrace
) >>= fun ty1
->
1040 ty (Tarraykind
(AKvarray ty1
))
1042 deserialization_error
1043 ~message
:(Printf.sprintf
1044 "Invalid number of type arguments to varray (expected 1): %d"
1049 | "varray_or_darray" ->
1050 get_array "args" (json
, keytrace
) >>= fun (args, keytrace
) ->
1051 begin match args with
1053 aux ty1 ~keytrace
:("0" :: keytrace
) >>= fun ty1
->
1054 ty (Tarraykind
(AKvarray_or_darray ty1
))
1057 deserialization_error
1058 ~message
:(Printf.sprintf
1059 "Invalid number of type arguments to varray_or_darray (expected 1): %d"
1065 get_bool "empty" (json
, keytrace
) >>= fun (empty, _empty_keytrace
) ->
1066 get_array "args" (json
, keytrace
) >>= fun (args, _args_keytrace
) ->
1067 begin match args with
1070 then ty (Tarraykind AKempty
)
1071 else ty (Tarraykind AKany
)
1074 aux ty1 ~keytrace
:("0" :: keytrace
) >>= fun ty1
->
1075 ty (Tarraykind
(AKvec ty1
))
1078 aux ty1 ~keytrace
:("0" :: keytrace
) >>= fun ty1
->
1079 aux ty2 ~keytrace
:("1" :: keytrace
) >>= fun ty2
->
1080 ty (Tarraykind
(AKmap
(ty1
, ty2
)))
1083 deserialization_error
1084 ~message
:(Printf.sprintf
1085 "Invalid number of type arguments to array (expected 0-2): %d"
1091 get_array "args" (json
, keytrace
) >>= fun (args, args_keytrace
) ->
1092 aux_args
args ~keytrace
:args_keytrace
>>= fun args -> ty (Ttuple
args)
1095 get_array "args" (json
, keytrace
) >>= fun (args, keytrace
) ->
1096 begin match args with
1098 aux nullable_ty ~keytrace
:("0" :: keytrace
) >>= fun nullable_ty
->
1099 ty (Toption nullable_ty
)
1101 deserialization_error
1102 ~message
:(Printf.sprintf
1103 "Unsupported number of args for nullable type: %d"
1109 get_string "name" (json
, keytrace
) >>= fun (name, keytrace
) ->
1110 begin match name with
1111 | "void" -> Ok
Nast.Tvoid
1112 | "int" -> Ok
Nast.Tint
1113 | "bool" -> Ok
Nast.Tbool
1114 | "float" -> Ok
Nast.Tfloat
1115 | "string" -> Ok
Nast.Tstring
1116 | "resource" -> Ok
Nast.Tresource
1117 | "num" -> Ok
Nast.Tnum
1118 | "arraykey" -> Ok
Nast.Tarraykey
1119 | "noreturn" -> Ok
Nast.Tnoreturn
1121 deserialization_error
1122 ~message
:("Unknown primitive type: " ^
name)
1124 end >>= fun prim_ty
->
1128 get_string "name" (json
, keytrace
) >>= fun (name, _name_keytrace
) ->
1130 match Decl_provider.get_class
name with
1134 (* Class may not exist (such as in non-strict modes). *)
1138 get_array "args" (json
, keytrace
) >>= fun (args, _args_keytrace
) ->
1139 aux_args
args ~keytrace
>>= fun tyl ->
1141 (* NB: "class" could have come from either a `Tapply` or a `Tclass`. Right
1142 now, we always return a `Tclass`. *)
1143 ty (Tclass
((class_pos, name), Nonexact
, tyl))
1149 get_array "fields" (json
, keytrace
) >>= fun (fields, fields_keytrace
) ->
1150 get_bool "is_array" (json
, keytrace
)
1151 >>= fun (is_array, _is_array_keytrace
) ->
1153 let unserialize_field
1157 (Ast_defs.shape_field_name
* locl
Typing_defs.shape_field_type
),
1158 deserialization_error
1160 get_val "name" (field_json
, keytrace
)
1161 >>= fun (name, name_keytrace
) ->
1163 (* We don't need position information for shape field names. They're
1164 only used for error messages and the like. *)
1165 let dummy_pos = Pos.none
in
1166 begin match name with
1167 | Hh_json.JSON_Number
name ->
1168 Ok
(Ast.SFlit_int
(dummy_pos, name))
1169 | Hh_json.JSON_String
name ->
1170 Ok
(Ast.SFlit_str
(dummy_pos, name))
1171 | Hh_json.JSON_Array
[
1172 Hh_json.JSON_String name1
;
1173 Hh_json.JSON_String name2
;
1175 Ok
(Ast.SFclass_const
((dummy_pos, name1
), (dummy_pos, name2
)))
1177 deserialization_error
1178 ~message
:"Unexpected format for shape field name"
1179 ~keytrace
:name_keytrace
1180 end >>= fun shape_field_name
->
1182 (* Optional field may be absent for shape-like arrays. *)
1183 begin match get_val "optional" (field_json
, keytrace
) with
1185 get_bool "optional" (field_json
, keytrace
)
1186 >>| fun (optional, _optional_keytrace
) ->
1188 | Error
_ -> Ok
false
1189 end >>= fun optional ->
1191 get_obj "type" (field_json
, keytrace
)
1192 >>= fun (shape_type
, shape_type_keytrace
) ->
1193 aux shape_type ~keytrace
:shape_type_keytrace
>>= fun shape_field_type
->
1194 let shape_field_type = {
1195 sft_optional
= optional;
1196 sft_ty
= shape_field_type;
1198 Ok
(shape_field_name
, shape_field_type)
1200 map_array
fields ~keytrace
:fields_keytrace ~f
:unserialize_field
1204 (* We don't have enough information to perfectly reconstruct shape-like
1205 arrays. We're missing the keys in the shape map of the shape fields. *)
1207 ~message
:"Cannot deserialize shape-like array type"
1210 get_bool "fields_known" (json
, keytrace
)
1211 >>= fun (fields_known, _fields_known_keytrace
) ->
1214 then FieldsFullyKnown
1215 else FieldsPartiallyKnown
Nast.ShapeMap.empty
1217 let fields = List.fold
1219 ~init
:Nast.ShapeMap.empty
1220 ~f
:(fun shape_map (k, v
) ->
1221 Nast.ShapeMap.add
k v
shape_map
1224 ty (Tshape
(fields_known, fields))
1227 get_array "args" (json
, keytrace
) >>= fun (args, keytrace
) ->
1228 aux_args
args ~keytrace
>>= fun tyl ->
1232 | "coroutine" as kind ->
1233 let ft_is_coroutine = (kind = "coroutine") in
1234 get_array "params" (json
, keytrace
) >>= fun (params, params_keytrace
) ->
1235 let params = map_array
1237 ~keytrace
:params_keytrace
1238 ~f
:(fun param ~keytrace
->
1239 get_string "callConvention" (param, keytrace
)
1240 >>= fun (callconv, callconv_keytrace
) ->
1241 begin match (string_to_param_mode callconv) with
1245 deserialization_error
1246 ~message
:("Unknown calling convention: " ^
callconv)
1247 ~keytrace
:callconv_keytrace
1248 end >>= fun callconv ->
1250 get_obj "type" (param, keytrace
)
1251 >>= fun (param_type
, param_type_keytrace
) ->
1252 aux param_type ~keytrace
:param_type_keytrace
1253 >>= fun param_type
->
1255 fp_type
= param_type
;
1258 (* Dummy values: these aren't currently serialized. *)
1261 fp_accept_disposable
= false;
1262 fp_mutability
= None
;
1263 fp_rx_annotation
= None
;
1267 params >>= fun ft_params
->
1269 get_obj "result" (json
, keytrace
) >>= fun (result, result_keytrace
) ->
1270 aux result ~keytrace
:result_keytrace
>>= fun ft_ret
->
1276 (* Dummy values: these aren't currently serialized. *)
1278 ft_deprecated
= None
;
1279 ft_abstract
= false;
1280 ft_arity
= Fstandard
(0, 0);
1281 ft_tparams
= ([], FTKtparams
);
1282 ft_where_constraints
= [];
1283 ft_reactive
= Nonreactive
;
1284 ft_return_disposable
= false;
1285 ft_mutability
= None
;
1286 ft_returns_mutable
= false;
1287 ft_decl_errors
= None
;
1288 ft_returns_void_to_rx
= false;
1293 ~message
:"Cannot deserialize lambda expression type"
1297 deserialization_error
1298 ~message
:(Printf.sprintf
1299 "Unknown or unsupported kind '%s' to convert to locl phase"
1301 ~keytrace
:kind_keytrace
1305 Hh_json.json
list ->
1308 keytrace
: Hh_json.Access.keytrace
->
1309 (a
, deserialization_error) result) ->
1310 keytrace
: Hh_json.Access.keytrace
->
1311 (a
list, deserialization_error) result =
1312 fun array ~f ~keytrace
->
1313 let array = List.mapi
array ~f
:(fun i elem
->
1314 f elem ~keytrace
:((string_of_int i
) :: keytrace
)
1319 (args: Hh_json.json
list)
1320 ~
(keytrace
: Hh_json.Access.keytrace
)
1321 : (locl
ty list, deserialization_error) result =
1322 map_array
args ~keytrace ~f
:aux
1325 (json
: Hh_json.json
)
1326 ~
(keytrace
: Hh_json.Access.keytrace
)
1327 : (locl
ty option, deserialization_error) result =
1328 let open Result.Monad_infix
in
1329 (* as-constraint is optional, check to see if it exists. *)
1330 match Hh_json.Access.get_obj "as" (json
, keytrace
) with
1331 | Ok
(as_json
, as_keytrace
) ->
1332 aux as_json ~keytrace
:as_keytrace
>>= fun as_ty
->
1334 | Error
(Hh_json.Access.Missing_key_error
_) ->
1336 | Error access_failure
->
1337 deserialization_error
1338 ~message
:("Invalid as-constraint: "
1339 ^
Hh_json.Access.access_failure_to_string access_failure
)
1347 let to_json = Json.from_type
1348 let json_to_locl_ty = Json.to_locl_ty
1350 (*****************************************************************************)
1351 (* Prints the internal type of a class, this code is meant to be used for
1352 * debugging purposes only.
1354 (*****************************************************************************)
1356 module PrintClass
= struct
1359 let bool = string_of_bool
1361 let contents = SSet.fold
(fun x acc
-> x^
" "^acc
) s "" in
1362 Printf.sprintf
"Set( %s)" contents
1365 let contents = Sequence.fold
s ~init
:"" ~f
:(fun acc
x -> x^
" "^acc
) in
1366 Printf.sprintf
"Seq( %s)" contents
1369 let line, start
, end_
= Pos.info_pos p
in
1370 Printf.sprintf
"(line %d: chars %d-%d)" line start end_
1372 let class_kind = function
1373 | Ast.Cabstract
-> "Cabstract"
1374 | Ast.Cnormal
-> "Cnormal"
1375 | Ast.Cinterface
-> "Cinterface"
1376 | Ast.Ctrait
-> "Ctrait"
1377 | Ast.Cenum
-> "Cenum"
1378 | Ast.Crecord
-> "Crecord"
1380 let constraint_ty tcopt
= function
1381 | (Ast.Constraint_as
, ty) -> "as " ^
(Full.to_string_decl tcopt
ty)
1382 | (Ast.Constraint_eq
, ty) -> "= " ^
(Full.to_string_decl tcopt
ty)
1383 | (Ast.Constraint_super
, ty) -> "super " ^
(Full.to_string_decl tcopt
ty)
1384 | (Ast.Constraint_pu_from
, ty) -> "from " ^
(Full.to_string_decl tcopt
ty)
1386 let variance = function
1387 | Ast.Covariant
-> "+"
1388 | Ast.Contravariant
-> "-"
1389 | Ast.Invariant
-> ""
1393 tp_name
= (position
, name);
1394 tp_constraints
= cstrl
;
1395 tp_reified
= reified
;
1396 tp_user_attributes
= _
1398 variance var^
pos position^
" "^
name^
" "^
1401 ~f
:(fun x acc
-> constraint_ty tcopt
x^
" "^acc
)
1405 | Nast.SoftReified
-> " soft reified"
1406 | Nast.Reified
-> " reified"
1408 let tparam_list tcopt
l =
1409 List.fold_right
l ~f
:(fun x acc
-> tparam tcopt
x^
", "^acc
) ~init
:""
1411 let class_elt tcopt
{ ce_visibility
; ce_synthesized
; ce_type
= lazy ty; _ } =
1413 match ce_visibility
with
1414 | Vpublic
-> "public"
1415 | Vprivate
_ -> "private"
1416 | Vprotected
_ -> "protected"
1418 let synth = (if ce_synthesized
then "synthetic " else "") in
1419 let type_ = Full.to_string_decl tcopt
ty in
1422 let class_elts tcopt m
=
1423 Sequence.fold m ~init
:"" ~f
:begin fun acc
(field
, v
) ->
1424 "("^field^
": "^
class_elt tcopt v^
") "^acc
1427 let class_elts_with_breaks tcopt m
=
1428 Sequence.fold m ~init
:"" ~f
:begin fun acc
(field
, v
) ->
1429 "\n"^
indent^field^
": "^
(class_elt tcopt v
)^acc
1432 let class_consts tcopt m
=
1433 Sequence.fold m ~init
:"" ~f
:begin fun acc
(field
, cc
) ->
1434 let synth = if cc
.cc_synthesized
then "synthetic " else "" in
1435 "("^field^
": "^
synth^
Full.to_string_decl tcopt cc
.cc_type^
") "^acc
1438 let typeconst tcopt
{
1441 ttc_constraint
= tc_constraint
;
1443 ttc_origin
= origin
;
1444 ttc_enforceable
= (_, enforceable
);
1446 let name = snd tc_name
in
1447 let ty x = Full.to_string_decl tcopt
x in
1449 match tc_constraint
with
1451 | Some
x -> " as "^
ty x
1456 | Some
x -> " = "^
ty x
1458 name^
constraint_^
type_^
" (origin:"^origin^
")" ^
1459 (if enforceable
then " (enforceable)" else "")
1461 let typeconsts tcopt m
=
1462 Sequence.fold m ~init
:"" ~f
:begin fun acc
(_, v
) ->
1463 "\n("^
(typeconst tcopt v
)^
")"^acc
1466 let ancestors tcopt m
=
1467 (* Format is as follows:
1469 * ! ParentCompletelyUnknown
1470 * ~ ParentPartiallyKnown (interface|abstract|trait)
1472 * ParentPartiallyKnown must inherit one of the ! Unknown parents, so that
1473 * sigil could be omitted *)
1474 Sequence.fold m ~init
:"" ~f
:begin fun acc
(field
, v
) ->
1475 let sigil, kind = match Decl_provider.get_class field
with
1478 (if Cls.members_fully_known cls
then " " else "~"),
1479 " ("^
class_kind (Cls.kind cls
)^
")"
1481 let ty_str = Full.to_string_decl tcopt v
in
1482 "\n"^
indent^
sigil^
" "^
ty_str^
kind^acc
1485 let constructor tcopt
(ce_opt
, consist
) =
1486 let consist_str = Format.asprintf
"(%a)" Pp_type.pp_consistent_kind consist
in
1487 let ce_str = match ce_opt
with
1489 | Some ce
-> class_elt tcopt ce
1490 in ce_str^
consist_str
1492 let req_ancestors tcopt xs
=
1493 Sequence.fold xs ~init
:"" ~f
:begin fun acc
(_p
, x) ->
1494 acc ^
Full.to_string_decl tcopt
x ^
", "
1497 let class_type tcopt c
=
1498 let tenv = Typing_env.empty tcopt
(Pos.filename
(Cls.pos c
)) None
in
1499 let tc_need_init = bool (Cls.need_init c
) in
1500 let tc_members_fully_known = bool (Cls.members_fully_known c
) in
1501 let tc_abstract = bool (Cls.abstract c
) in
1502 let tc_deferred_init_members = sset @@
1503 if shallow_decl_enabled ()
1505 match Shallow_classes_heap.get
(Cls.name c
) with
1506 | Some cls
-> Typing_deferred_members.class_
tenv cls
1507 | None
-> SSet.empty
1509 Cls.deferred_init_members c
1511 let tc_kind = class_kind (Cls.kind c
) in
1512 let tc_name = (Cls.name c
) in
1513 let tc_tparams = tparam_list tcopt
(Cls.tparams c
) in
1514 let tc_consts = class_consts tcopt
(Cls.consts c
) in
1515 let tc_typeconsts = typeconsts tcopt
(Cls.typeconsts c
) in
1516 let tc_props = class_elts tcopt
(Cls.props c
) in
1517 let tc_sprops = class_elts tcopt
(Cls.sprops c
) in
1518 let tc_methods = class_elts_with_breaks tcopt
(Cls.methods c
) in
1519 let tc_smethods = class_elts_with_breaks tcopt
(Cls.smethods c
) in
1520 let tc_construct = constructor tcopt
(Cls.construct c
) in
1521 let tc_ancestors = ancestors tcopt
(Cls.all_ancestors c
) in
1522 let tc_req_ancestors = req_ancestors tcopt
(Cls.all_ancestor_reqs c
) in
1523 let tc_req_ancestors_extends = sseq (Cls.all_ancestor_req_names c
) in
1524 let tc_extends = sseq (Cls.all_extends_ancestors c
) in
1525 "tc_need_init: "^
tc_need_init^
"\n"^
1526 "tc_members_fully_known: "^
tc_members_fully_known^
"\n"^
1527 "tc_abstract: "^
tc_abstract^
"\n"^
1528 "tc_deferred_init_members: "^
tc_deferred_init_members^
"\n"^
1529 "tc_kind: "^
tc_kind^
"\n"^
1530 "tc_name: "^
tc_name^
"\n"^
1531 "tc_tparams: "^
tc_tparams^
"\n"^
1532 "tc_consts: "^
tc_consts^
"\n"^
1533 "tc_typeconsts: "^
tc_typeconsts^
"\n"^
1534 "tc_props: "^
tc_props^
"\n"^
1535 "tc_sprops: "^
tc_sprops^
"\n"^
1536 "tc_methods: "^
tc_methods^
"\n"^
1537 "tc_smethods: "^
tc_smethods^
"\n"^
1538 "tc_construct: "^
tc_construct^
"\n"^
1539 "tc_ancestors: "^
tc_ancestors^
"\n"^
1540 "tc_extends: "^
tc_extends^
"\n"^
1541 "tc_req_ancestors: "^
tc_req_ancestors^
"\n"^
1542 "tc_req_ancestors_extends: "^
tc_req_ancestors_extends^
"\n"^
1546 module PrintFun
= struct
1548 let fparam tcopt
{ fp_name
= sopt
; fp_type
= ty; _ } =
1549 let s = match sopt
with
1552 s ^
" " ^
(Full.to_string_decl tcopt
ty) ^
", "
1554 let farity = function
1555 | Fstandard
(min
, max
) -> Printf.sprintf
"non-variadic: %d to %d" min max
1556 | Fvariadic
(min
, _) ->
1557 Printf.sprintf
"variadic: ...$arg-style (PHP 5.6); min: %d" min
1558 | Fellipsis
(min
, _) -> Printf.sprintf
"variadic: ...-style (Hack); min: %d" min
1560 let fparams tcopt
l =
1561 List.fold_right
l ~f
:(fun x acc
-> (fparam tcopt
x)^acc
) ~init
:""
1563 let fun_type tcopt f
=
1564 let ft_pos = PrintClass.pos f
.ft_pos in
1565 let ft_abstract = string_of_bool f
.ft_abstract in
1566 let ft_arity = farity f
.ft_arity in
1567 let tparams = PrintClass.tparam_list tcopt
(fst f
.ft_tparams
) in
1568 let instantiate_tparams = match snd f
.ft_tparams
with
1569 | FTKtparams
-> "FTKtparams"
1570 | FTKinstantiated_targs
-> "FTKinstantiated_targs" in
1571 let ft_params = fparams tcopt f
.ft_params in
1572 let ft_ret = Full.to_string_decl tcopt f
.ft_ret in
1573 "ft_pos: "^
ft_pos^
"\n"^
1574 "ft_abstract: "^
ft_abstract^
"\n"^
1575 "ft_arity: "^
ft_arity^
"\n"^
1576 "ft_tparams: ("^
tparams^
", "^
instantiate_tparams^
")\n"^
1577 "ft_params: "^
ft_params^
"\n"^
1578 "ft_ret: "^
ft_ret^
"\n"^
1582 module PrintTypedef
= struct
1584 let typedef tcopt
= function
1585 | {td_pos
; td_vis
= _; td_tparams
; td_constraint
; td_type
;
1586 td_decl_errors
= _;} ->
1587 let tparaml_s = PrintClass.tparam_list tcopt td_tparams
in
1588 let constr_s = match td_constraint
with
1590 | Some constr
-> Full.to_string_decl tcopt constr
in
1591 let ty_s = Full.to_string_decl tcopt td_type
in
1592 let pos_s = PrintClass.pos td_pos
in
1594 "tparaml: "^
tparaml_s^
"\n"^
1595 "constraint: "^
constr_s^
"\n"^
1601 (*****************************************************************************)
1603 (*****************************************************************************)
1605 let error env ty = ErrorString.to_string env ty
1606 let suggest: type a
. a
ty -> _ = fun ty -> Suggest.type_ ty
1607 let full env ty = Full.to_string Doc.text
env ty
1608 let full_rec env n
ty = Full.to_string_rec env n
ty
1609 let full_strip_ns env ty = Full.to_string_strip_ns env ty
1610 let full_with_identity = Full.to_string_with_identity
1612 Full.debug_mode := true;
1613 let f_str = full_strip_ns env ty in
1614 Full.debug_mode := false;
1616 let class_ tcopt c
= PrintClass.class_type tcopt c
1617 let gconst tcopt gc
= Full.to_string_decl tcopt
(fst gc
)
1618 let fun_ tcopt f
= PrintFun.fun_type tcopt f
1619 let typedef tcopt td
= PrintTypedef.typedef tcopt td
1620 let constraints_for_type env ty =
1621 Full.constraints_for_type Doc.text
env ty
1622 |> Option.map ~f
:(Libhackfmt.format_doc_unbroken
Full.format_env)
1623 |> Option.map ~f
:String.strip
1624 let class_kind c_kind final
= ErrorString.class_kind c_kind final
1625 let subtype_prop env prop
=
1626 let rec subtype_prop = function
1627 | Unsat
_ -> "UNSAT"
1630 "(" ^
(String.concat ~sep
:" && " (List.map ~f
:subtype_prop ps
)) ^
")"
1631 | Disj
[] -> "FALSE"
1633 "(" ^
(String.concat ~sep
:" || " (List.map ~f
:subtype_prop ps
)) ^
")"
1634 | IsSubtype
(ty1
, ty2
) ->
1635 debug env ty1 ^
" <: " ^
debug env ty2
1636 | IsEqual
(ty1
, ty2
) ->
1637 debug env ty1 ^
" = " ^
debug env ty2
in
1638 let p_str = subtype_prop prop
in