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.
15 open Typing_logic_helpers
16 module Reason
= Typing_reason
17 module Env
= Typing_env
18 module Inter
= Typing_intersection
19 module Subst
= Decl_subst
20 module TUtils
= Typing_utils
21 module SN
= Naming_special_names
22 module Phase
= Typing_phase
23 module TL
= Typing_logic
24 module Cls
= Decl_provider.Class
25 module ITySet
= Internal_type_set
26 module MakeType
= Typing_make_type
27 module Partial
= Partial_provider
28 module ShapeMap
= Nast.ShapeMap
29 module ShapeSet
= Ast_defs.ShapeSet
33 seen_generic_params
: SSet.t
option;
35 treat_dynamic_as_bottom
: bool;
36 on_error
: Errors.typing_error_callback
;
39 let empty_seen = Some
SSet.empty
42 ?
(seen_generic_params
= empty_seen)
43 ?
(no_top_bottom
= false)
44 ?
(treat_dynamic_as_bottom
= false)
46 { seen_generic_params
; no_top_bottom
; treat_dynamic_as_bottom
; on_error
}
48 let add_seen_generic subtype_env name
=
49 match subtype_env
.seen_generic_params
with
51 { subtype_env
with seen_generic_params
= Some
(SSet.add name seen
) }
54 type reactivity_extra_info
= {
55 method_info
: (* method_name *) (string * (* is_static *) bool) option;
56 class_ty
: phase_ty
option;
57 parent_class_ty
: phase_ty
option;
60 let empty_extra_info =
61 { method_info
= None
; class_ty
= None
; parent_class_ty
= None
}
63 module ConditionTypes
= struct
64 let try_get_class_for_condition_type (env
: env
) (ty
: decl_ty
) =
65 match TUtils.try_unwrap_class_type ty
with
67 | Some
(_
, ((_
, x
) as sid
), _
) ->
69 match Env.get_class env x
with
71 | Some cls
-> Some
(sid
, cls
)
74 let try_get_method_from_condition_type
75 (env
: env
) (ty
: decl_ty
) (is_static
: bool) (method_name
: string) =
76 match try_get_class_for_condition_type env ty
with
87 let localize_condition_type (env
: env
) (ty
: decl_ty
) : locl_ty
=
88 (* if condition type is generic - we cannot specify type argument in attribute.
89 For cases when we check if containing type is a subtype of condition type
90 if condition type is generic instantiate it with TAny's *)
93 match try_get_class_for_condition_type env
ty with
95 | Some
(_
, cls
) when List.is_empty
(Cls.tparams cls
) -> ty
96 | Some
(((p
, _
) as sid
), cls
) ->
98 List.map
(Cls.tparams cls
) ~f
:(fun { tp_name
= (p
, x
); _
} ->
99 (* TODO(T69551141) handle type arguments *)
100 MakeType.generic
(Reason.Rwitness p
) x
)
102 let subst = Decl_instantiate.make_subst
(Cls.tparams cls
) [] in
103 let ty = MakeType.apply
(Reason.Rwitness p
) sid
params in
104 Decl_instantiate.instantiate
subst ty
106 let ety_env = Phase.env_with_self env
in
107 let (_
, t
) = Phase.localize ~
ety_env env
ty in
111 | (r
, Toption
ty) -> mk
(r
, Toption
(do_localize ty))
112 | _
-> do_localize ty
115 (* Fetch all the constraints of a `Tpu_type_access(tparam, tyname)`, which
116 * are stored in a PU definition, and filter them to only keep upper bounds
118 let get_tpu_type_param_upper_bounds env tparam tyname
=
119 (* Filter the decl type parameter constraints to only keep the `as` ones *)
120 let filter_constraints env
ety_env decl_tparam
=
121 List.filter_map_env env decl_tparam
.tp_constraints ~f
:(fun env
(ck
, dty
) ->
123 (* Only keep the "as" constraints *)
124 | Ast_defs.Constraint_as
->
125 let (env
, lty
) = Phase.localize ~
ety_env env dty
in
129 (* when tparam is bound by a Tpu(C, E), we look at the definition
130 * of the PU to get the constraints on `case type tyname`.
131 * We accumulate such constraints in `acc`
133 let get_case_type_constraints env cls enum acc
=
134 (* Get the type parameter associated to tyname in this PU *)
135 let (env
, info
) = TUtils.class_get_pu_type env cls enum tyname
in
139 | Some
(ety_env, (_
, decl_tparam
)) ->
140 filter_constraints env
ety_env decl_tparam
142 (env
, List.rev_append acc ltys
)
144 (* Get upper bounds of the tparam generic *)
145 let upper_bounds = Env.get_upper_bounds env tparam
in
147 (fun bound
(env
, acc
) ->
148 match get_node bound
with
149 (* Only inspect Tpu bounds *)
150 | Tpu
(cls
, (_
, enum
)) -> get_case_type_constraints env cls enum acc
155 (* Given a pair of types `ty_sub` and `ty_super` attempt to apply simplifications
156 * and add to the accumulated constraints in `constraints` any necessary and
157 * sufficient [(t1,ck1,u1);...;(tn,ckn,un)] such that
158 * ty_sub <: ty_super iff t1 ck1 u1, ..., tn ckn un
159 * where ck is `as` or `=`. Essentially we are making solution-preserving
160 * simplifications to the subtype assertion, for now, also generating equalities
161 * as well as subtype assertions, for backwards compatibility with use of
164 * If `constraints = []` is returned then the subtype assertion is valid.
166 * If the subtype assertion is unsatisfiable then return `failed = Some f`
167 * where `f` is a `unit-> unit` function that records an error message.
168 * (Sometimes we don't want to call this function e.g. when just checking if
171 * Elide singleton unions, treat invariant generics as both-ways
172 * subtypes, and actually chase hierarchy for extends and implements.
174 * Annoyingly, we need to pass env back too, because Typing_phase.localize
175 * expands type constants. (TODO: work out a better way of handling this)
178 * If assertion is valid (e.g. string <: arraykey) then
179 * result can be the empty list (i.e. nothing is added to the result)
180 * If assertion is unsatisfiable (e.g. arraykey <: string) then
181 * we record this in the failed field of the result.
184 (** Check that a mutability type is a subtype of another mutability type *)
186 ~
(is_receiver
: bool)
189 (mut_sub
: param_mutability
option)
191 (mut_super
: param_mutability
option)
195 | None
-> "immutable"
196 | Some Param_owned_mutable
-> "owned mutable"
197 | Some Param_borrowed_mutable
-> "mutable"
198 | Some Param_maybe_mutable
-> "maybe-mutable"
200 (* maybe-mutable <------immutable
202 <--mutable <-- owned mutable *)
203 match (mut_sub
, mut_super
) with
204 (* immutable is not compatible with mutable *)
205 | (None
, Some
(Param_borrowed_mutable
| Param_owned_mutable
))
206 (* mutable is not compatible with immutable *)
207 | (Some
(Param_borrowed_mutable
| Param_owned_mutable
), None
)
208 (* borrowed mutable is not compatible with owned mutable *)
209 | (Some Param_borrowed_mutable
, Some Param_owned_mutable
)
210 (* maybe-mutable is not compatible with immutable/mutable *)
211 | ( Some Param_maybe_mutable
,
212 (None
| Some
(Param_borrowed_mutable
| Param_owned_mutable
)) ) ->
215 Errors.mutability_mismatch
221 subtype_env
.on_error
)
225 let log_subtype_i ~level ~this_ty ~function_name env ty_sub ty_super
=
227 log_with_level env
"sub" level
(fun () ->
229 [Log_type_i
("ty_sub", ty_sub
); Log_type_i
("ty_super", ty_super
)]
232 Option.value_map this_ty ~default
:types ~f
:(fun ty ->
233 Log_type
("this_ty", ty) :: types)
236 (Reason.to_pos
(reason ty_sub
))
238 [Log_head
(function_name
, types)]))
240 let log_subtype ~this_ty ~function_name env ty_sub ty_super
=
248 let is_final_and_not_contravariant env id
=
249 let class_def = Env.get_class env id
in
251 | Some class_ty
-> TUtils.class_is_final_and_not_contravariant class_ty
254 (** Make all types appearing in the given type a Tany, e.g.
255 - for A<B> return A<_>
256 - for function(A): B return function (_): _
261 inherit Type_mapper.deep_type_mapper
as super
263 method! on_type env _ty
= (env
, mk
(r
, Typing_defs.make_tany
()))
266 let (_
, ty) = super#on_type env
ty in
272 let find_type_with_exact_negation env tyl
=
273 let rec find env tyl acc_tyl
=
275 | [] -> (env
, None
, acc_tyl
)
277 let (env
, non_ty
) = TUtils.non env
(get_reason
ty) ty TUtils.ApproxDown
in
278 let nothing = MakeType.nothing Reason.none
in
279 if ty_equal non_ty
nothing then
280 find env tyl'
(ty :: acc_tyl
)
282 (env
, Some non_ty
, tyl'
@ acc_tyl
)
286 let rec describe_ty_super env ?
(short
= false) ty =
288 Typing_print.with_blank_tyvars
(fun () ->
289 Typing_print.full_strip_ns_i env
ty)
291 let default () = print ty in
294 let (env
, ty) = Env.expand_type env
ty in
295 (match get_node
ty with
297 let upper_bounds = ITySet.elements
(Env.get_tyvar_upper_bounds env v
) in
298 (* The constraint graph is transitively closed so we can filter tyvars. *)
299 let is_not_tyvar = function
300 | LoclType t
-> not
(is_tyvar t
)
303 let upper_bounds = List.filter
upper_bounds ~f
:is_not_tyvar in
304 (match upper_bounds with
305 | [] -> "some type not known yet"
307 let (locl_tyl
, cstr_tyl
) = List.partition_tf tyl ~f
:is_locl_type
in
315 match (locl_tyl
, cstr_tyl
) with
316 | (_
:: _
, _
:: _
) -> " and "
329 prefix ^
String.concat ~
sep:" & " (List.map tyl ~f
:print)
334 (List.map cstr_tyl ~f
:(describe_ty_super env
))
336 prefix ^
locl_descr ^
sep ^
cstr_descr)
337 | Toption
ty when is_tyvar
ty ->
338 "null or " ^
describe_ty_super env
(LoclType
ty)
340 | ConstraintType
ty ->
341 (match deref_constraint_type
ty with
342 | (_
, Thas_member hm
) ->
343 let { hm_name
= (_
, name
); hm_type
= _
; hm_class_id
= _
} = hm
in
344 Printf.sprintf
"an object with member `%s`" name
345 | (_
, Tdestructure _
) ->
346 Typing_print.with_blank_tyvars
(fun () ->
347 Typing_print.full_strip_ns_i env
(ConstraintType
ty))
348 | (_
, TCunion
(lty
, cty
)) ->
351 (describe_ty_super env
(LoclType lty
))
352 (describe_ty_super env
(ConstraintType cty
))
353 | (_
, TCintersection
(lty
, cty
)) ->
356 (describe_ty_super env
(LoclType lty
))
357 (describe_ty_super env
(ConstraintType cty
)))
359 (** Process the constraint proposition. There should only be errors left now,
360 i.e. empty disjunction with error functions we call here. *)
361 let rec process_simplify_subtype_result prop
=
363 | TL.IsSubtype
(_ty1
, _ty2
) ->
364 (* All subtypes should have been resolved *)
365 failwith
"unexpected subtype assertion"
367 (* All coercions should have been resolved *)
368 failwith
"unexpected coercions assertion"
370 (* Evaluates list from left-to-right so preserves order of conjuncts *)
371 List.for_all ~f
:process_simplify_subtype_result props
375 | TL.Disj _
-> failwith
"non-empty disjunction"
378 ~
(subtype_env
: subtype_env
)
379 ?
(this_ty
: locl_ty
option = None
)
382 simplify_subtype_i ~subtype_env ~this_ty
(LoclType ty_sub
) (LoclType ty_super
)
384 (* Attempt to "solve" a subtype assertion ty_sub <: ty_super.
385 * Return a proposition that is equivalent, but simpler, than
386 * the original assertion. Fail with Unsat error_function if
387 * the assertion is unsatisfiable. Some examples:
388 * string <: arraykey ==> True (represented as Conj [])
389 * (For covariant C and a type variable v)
390 * C<string> <: C<v> ==> string <: v
391 * (Assuming that C does *not* implement interface J)
393 * (Assuming we have T <: D in tpenv, and class D implements I)
394 * vec<T> <: vec<I> ==> True
395 * This last one would be left as T <: I if seen_generic_params is None
397 and simplify_subtype_i
398 ~
(subtype_env
: subtype_env
)
399 ?
(this_ty
: locl_ty
option = None
)
400 (ty_sub
: internal_type
)
401 (ty_super
: internal_type
)
402 env
: env
* TL.subtype_prop
=
406 ~function_name
:"simplify_subtype"
410 let (env
, ety_super
) = Env.expand_internal_type env ty_super
in
411 let (env
, ety_sub
) = Env.expand_internal_type env ty_sub
in
412 let fail_with_suffix suffix
=
413 let r_super = reason ety_super
in
414 let r_sub = reason ety_sub
in
415 let ty_super_descr = describe_ty_super env ety_super
in
417 Typing_print.with_blank_tyvars
(fun () ->
418 Typing_print.full_strip_ns_i env ety_sub
)
420 let (ty_super_descr, ty_sub_descr) =
421 if String.equal
ty_super_descr ty_sub_descr then
422 ( "exactly the type " ^
ty_super_descr,
423 "the nonexact type " ^
ty_sub_descr )
425 (ty_super_descr, ty_sub_descr)
427 let left = Reason.to_string
("Expected " ^
ty_super_descr) r_super in
428 let right = Reason.to_string
("But got " ^
ty_sub_descr) r_sub @ suffix
in
429 match (r_super, r_sub) with
430 | (Reason.Rcstr_on_generics
(p
, tparam
), _
)
431 | (_
, Reason.Rcstr_on_generics
(p
, tparam
)) ->
432 Errors.violated_constraint p tparam
left right subtype_env
.on_error
433 | _
-> subtype_env
.on_error
(left @ right)
435 let fail () = fail_with_suffix [] in
436 let ( ||| ) = ( ||| ) ~
fail in
437 (* We *know* that the assertion is unsatisfiable *)
438 let invalid_with f
= invalid ~
fail:f env
in
439 let invalid_env env
= invalid ~
fail env
in
440 let invalid_env_with env f
= invalid ~
fail:f env
in
441 let invalid () = invalid_with fail in
442 (* We *know* that the assertion is valid *)
443 let valid_env env
= valid env
in
444 let valid () = valid_env env
in
445 (* We don't know whether the assertion is valid or not *)
446 let default () = (env
, TL.IsSubtype
(ety_sub
, ety_super
)) in
447 (* This function contains typing rules that are based solely on the subtype
448 * if you need to pattern match on the super type it should NOT be included
451 let default_subtype env
=
452 let ty_sub = ety_sub
in
453 let ty_super = ety_super
in
455 | ConstraintType cty_sub
->
457 match deref_constraint_type cty_sub
with
458 | (_
, TCunion
(lty_sub
, cty_sub
)) ->
460 |> simplify_subtype_i ~subtype_env
(LoclType lty_sub
) ty_super
461 &&& simplify_subtype_i ~subtype_env
(ConstraintType cty_sub
) ty_super
462 | (_
, TCintersection
(lty_sub
, cty_sub
)) ->
464 |> simplify_subtype_i ~subtype_env
(LoclType lty_sub
) ty_super
465 ||| simplify_subtype_i ~subtype_env
(ConstraintType cty_sub
) ty_super
472 * t1 <: t /\ ... /\ tn <: t
473 * We want this even if t is a type variable e.g. consider
477 match deref
ty_sub with
479 List.fold_left tyl ~init
:(env
, TL.valid) ~f
:(fun res
ty_sub ->
480 res
&&& simplify_subtype_i ~subtype_env
(LoclType
ty_sub) ty_super)
482 if subtype_env
.no_top_bottom
then
486 | (_
, Tvar _
) -> default ()
487 | (r_sub, Tintersection tyl
) ->
488 (* A & B <: C iif A <: C | !B *)
489 (match find_type_with_exact_negation env tyl
with
490 | (env
, Some non_ty
, tyl
) ->
491 let (env
, ty_super) =
492 TUtils.union_i env
(get_reason non_ty
) ty_super non_ty
494 let ty_sub = MakeType.intersection
r_sub tyl
in
495 simplify_subtype_i ~subtype_env
(LoclType
ty_sub) ty_super env
497 (* It's sound to reduce t1 & t2 <: t to (t1 <: t) || (t2 <: t), but
502 ~init
:(env
, TL.invalid ~
fail)
503 ~f
:(fun res
ty_sub ->
504 let ty_sub = LoclType
ty_sub in
505 res
||| simplify_subtype_i ~subtype_env ~this_ty
ty_sub ty_super))
506 | (_
, Tgeneric
(name_sub
, _tyargs
)) ->
507 (* TODO(T69551141) handle type arguments *)
508 (match subtype_env
.seen_generic_params
with
511 (* If we've seen this type parameter before then we must have gone
512 * round a cycle so we fail
514 if SSet.mem name_sub seen
then
517 (* If the generic is actually an expression dependent type,
518 we need to update this_ty
522 DependentKind.is_generic_dep_ty name_sub
523 && Option.is_none
this_ty
529 let subtype_env = add_seen_generic subtype_env name_sub
in
530 (* Otherwise, we collect all the upper bounds ("as" constraints) on
531 the generic parameter, and check each of these in turn against
532 ty_super until one of them succeeds
534 let rec try_bounds tyl env
=
537 (* Try an implicit mixed = ?nonnull bound before giving up.
538 This can be useful when checking T <: t, where type t is
539 equivalent to but syntactically different from ?nonnull.
540 E.g., if t is a generic type parameter T with nonnull as
544 Reason.Rimplicit_upper_bound
(get_pos
ty_sub, "?nonnull")
546 let tmixed = LoclType
(MakeType.mixed
r) in
548 |> simplify_subtype_i ~
subtype_env ~
this_ty tmixed ty_super
559 ||| simplify_subtype_i
567 (Typing_set.elements
(Env.get_upper_bounds env name_sub
)))
568 |> (* Turn error into a generic error about the type parameter *)
570 | (_
, Tdynamic
) when subtype_env.treat_dynamic_as_bottom
-> valid ()
571 | (_
, Tpu_type_access
((_pm
, msub
), (_pn
, nsub
))) ->
572 (* If member is actually an expression dependent type,
573 * we need to update this_ty
576 if DependentKind.is_generic_dep_ty msub
&& Option.is_none
this_ty
583 * We are checking if msub:@nsub is a subtype of ty_super.
584 * Since msub is a generic parameter, we are scanning all of its
585 * upper bounds and look for all C:@E.
586 * We then scan the PU definition of these C:@E to gather the 'as'
587 * constraints on the type `case type nsub`.
589 * Finally, we attempt to use those in recursive subtype calls
590 * to check if they are <: ty_super.
592 let (env
, upper_bounds) =
593 get_tpu_type_param_upper_bounds env msub nsub
595 let rec try_bounds tyl env
=
597 | [] -> invalid_env env
608 ||| simplify_subtype_i
614 env
|> try_bounds upper_bounds |> if_unsat
invalid
618 (* We further refine the default subtype case for rules that apply to all
619 * LoclTypes but not to ConstraintTypes
621 let default_subtype env
=
622 let ty_sub = ety_sub
in
623 let ty_super = ety_super
in
625 | LoclType
ty_super ->
627 | ConstraintType _
-> default_subtype env
630 match deref
ty_sub with
631 | (_
, Tvar _
) when subtype_env.treat_dynamic_as_bottom
->
632 (env
, TL.Coerce
(ty_sub, ty_super))
633 | (_
, Tnewtype
(_
, _
, ty)) ->
634 simplify_subtype ~
subtype_env ~
this_ty ty ty_super env
635 | (_
, Tdependent
(_
, ty)) ->
636 let this_ty = Option.first_some
this_ty (Some
ty_sub) in
637 simplify_subtype ~
subtype_env ~
this_ty ty ty_super env
639 if subtype_env.no_top_bottom
then
642 let ty_sub = anyfy env
r_sub ty_super in
643 simplify_subtype ~
subtype_env ~
this_ty ty_sub ty_super env
644 | (r_sub, Tprim
Nast.Tvoid
) ->
646 Reason.Rimplicit_upper_bound
(Reason.to_pos
r_sub, "?nonnull")
655 | _
-> default_subtype env
657 | ConstraintType _
-> default_subtype env
660 (* First deal with internal constraint types *)
661 | ConstraintType cty_super
->
663 match deref_constraint_type cty_super
with
664 | (_
, TCintersection
(lty
, cty
)) ->
666 | LoclType t
when is_union t
-> default_subtype env
667 | ConstraintType t
when is_constraint_type_union t
->
671 |> simplify_subtype_i ~
subtype_env ty_sub (LoclType lty
)
672 &&& simplify_subtype_i ~
subtype_env ty_sub (ConstraintType cty
))
673 | (_
, TCunion
(lty_super
, cty_super
)) ->
675 | ConstraintType cty
when is_constraint_type_union cty
->
677 | ConstraintType _
->
679 |> simplify_subtype_i ~
subtype_env ty_sub (LoclType lty_super
)
680 ||| simplify_subtype_i ~
subtype_env ty_sub (ConstraintType cty_super
)
683 (match deref lty
with
685 let ty_null = MakeType.null
r in
694 if TL.is_unsat p1
then
706 | (_
, (Tintersection _
| Tunion _
| Terr
| Tvar _
)) ->
710 |> simplify_subtype_i ~
subtype_env ty_sub (LoclType lty_super
)
711 ||| simplify_subtype_i
714 (ConstraintType cty_super
)
715 ||| default_subtype))
716 | (r_super, Tdestructure
{ d_required
; d_optional
; d_variadic
; d_kind
})
718 (* List destructuring *)
719 let destructure_array t env
=
720 (* If this is a splat, there must be a variadic box to receive the elements
721 * but for list(...) destructuring this is not required. Example:
723 * function f(int $i): void {}
724 * function g(vec<int> $v): void {
725 * list($a) = $v; // ok (but may throw)
730 | Reason.Runpack_param
(_
, fpos, _
) -> fpos
731 | _
-> Reason.to_pos
r_super
733 match (d_kind
, d_required
, d_variadic
) with
734 | (SplatUnpack
, _
:: _
, _
) ->
735 (* return the env so as not to discard the type variable that might
736 have been created for the Traversable type created below. *)
737 invalid_env_with env
(fun () ->
738 Errors.unpack_array_required_argument
739 (Reason.to_pos
r_super)
741 subtype_env.on_error
)
742 | (SplatUnpack
, [], None
) ->
743 invalid_env_with env
(fun () ->
744 Errors.unpack_array_variadic_argument
745 (Reason.to_pos
r_super)
747 subtype_env.on_error
)
748 | (SplatUnpack
, [], Some _
)
749 | (ListDestructure
, _
, _
) ->
750 List.fold d_required ~init
:(env
, TL.valid) ~f
:(fun res ty_dest
->
751 res
&&& simplify_subtype ~
subtype_env ~
this_ty t ty_dest
)
753 List.fold d_optional ~init
:(env
, TL.valid) ~f
:(fun res ty_dest
->
754 res
&&& simplify_subtype ~
subtype_env ~
this_ty t ty_dest
)
756 Option.value_map ~
default:(env
, TL.valid) d_variadic ~f
:(fun vty
->
757 simplify_subtype ~
subtype_env ~
this_ty t vty env
)
760 let destructure_tuple r ts env
=
761 (* First fill the required elements. If there are insufficient elements, an error is reported.
762 * Fill as many of the optional elements as possible, and the remainder are unioned into the
763 * variadic element. Example:
765 * (float, bool, string, int) <: Tdestructure(#1, opt#2, ...#3) =>
766 * float <: #1 /\ bool <: #2 /\ string <: #3 /\ int <: #3
768 * (float, bool) <: Tdestructure(#1, #2, opt#3) =>
769 * float <: #1 /\ bool <: #2
771 let len_ts = List.length ts
in
772 let len_required = List.length d_required
in
774 let (epos
, fpos, prefix) =
776 | Reason.Runpack_param
(epos
, fpos, c
) -> (epos
, fpos, c
)
777 | _
-> (Reason.to_pos
r_super, Reason.to_pos
r, 0)
779 invalid_env_with env
(fun () ->
781 (prefix + len_required)
785 (Some
subtype_env.on_error
))
787 if len_ts < len_required then
788 arity_error Errors.typing_too_few_args
790 let len_optional = List.length d_optional
in
791 let (ts_required
, remain
) = List.split_n ts
len_required in
792 let (ts_optional
, ts_variadic
) = List.split_n remain
len_optional in
796 ~init
:(env
, TL.valid)
797 ~f
:(fun res
ty ty_dest
->
798 res
&&& simplify_subtype ~
subtype_env ~
this_ty ty ty_dest
)
800 let len_ts_opt = List.length ts_optional
in
801 let d_optional_part =
802 if len_ts_opt < len_optional then
803 List.take d_optional
len_ts_opt
810 ~init
:(env
, TL.valid)
811 ~f
:(fun res
ty ty_dest
->
812 res
&&& simplify_subtype ~
subtype_env ~
this_ty ty ty_dest
)
814 match (ts_variadic
, d_variadic
) with
815 | (vars
, Some vty
) ->
816 List.fold vars ~init
:(env
, TL.valid) ~f
:(fun res
ty ->
817 res
&&& simplify_subtype ~
subtype_env ~
this_ty ty vty
)
818 | ([], None
) -> valid ()
820 (* Elements remain but we have nowhere to put them *)
821 arity_error Errors.typing_too_many_args
826 | ConstraintType _
-> default_subtype env
828 (match deref
ty_sub with
829 | (r, Ttuple tyl
) -> env
|> destructure_tuple r tyl
830 | (r, Tclass
((_
, x
), _
, tyl
))
831 when String.equal x
SN.Collections.cPair
->
832 env
|> destructure_tuple r tyl
833 | (_
, Tclass
((_
, x
), _
, [elt_type
]))
834 when String.equal x
SN.Collections.cVector
835 || String.equal x
SN.Collections.cImmVector
836 || String.equal x
SN.Collections.cVec
837 || String.equal x
SN.Collections.cConstVector
->
838 env
|> destructure_array elt_type
839 | (_
, Tvarray elt_type
) -> env
|> destructure_array elt_type
840 | (_
, Tdynamic
) -> env
|> destructure_array ty_sub
841 (* TODO: should remove these any cases *)
843 let any = mk
(r, Typing_defs.make_tany
()) in
844 env
|> destructure_array any
845 | (_
, (Tunion _
| Tintersection _
| Tgeneric _
| Tvar _
)) ->
846 (* TODO(T69551141) handle type arguments of Tgeneric? *)
852 (* Allow splatting of arbitrary Traversables *)
853 let (env
, ty_inner
) =
854 Env.fresh_type env
(Reason.to_pos
r_super)
856 let traversable = MakeType.traversable r_super ty_inner
in
858 |> simplify_subtype ~
subtype_env ~
this_ty ty_sub traversable
859 &&& destructure_array ty_inner
862 Typing_print.with_blank_tyvars
(fun () ->
863 Typing_print.full_strip_ns env
ty_sub)
866 |> if_unsat
@@ fun () ->
867 invalid_with (fun () ->
868 Errors.invalid_destructure
869 (Reason.to_pos
r_super)
872 subtype_env.on_error
)
877 { hm_name
= name
; hm_type
= member_ty
; hm_class_id
= class_id
} ) ->
879 | ConstraintType cty
->
881 match deref_constraint_type cty
with
887 hm_class_id
= cid_sub
;
889 if Nast.equal_sid name_sub name
&& class_id_equal cid_sub class_id
891 simplify_subtype ~
subtype_env ~
this_ty ty_sub member_ty env
894 | _
-> default_subtype env
897 (match deref
ty_sub with
898 | (_
, (Tvar _
| Tunion _
| Terr
)) -> default_subtype env
899 | (_
, Tintersection tyl
)
900 when let (_
, non_ty_opt
, _
) =
901 find_type_with_exact_negation env tyl
903 Option.is_some non_ty_opt
->
905 (* Ideally, we'd want this case to come after the case with an intersection
906 on the left, to deal properly with (#1 & A) <: Thas_member(#2) by potentially
907 adding an upper bound to #1, but that would result in a disjunction
908 which we don't handle very well at the moment.
909 TODO: when we have a better treatment of disjunctions, move that case after
910 the case with an intersection on the left.
911 For now, if there is an intersection on the left here,
912 we rely on how obj_get itself treats intersections. If that
913 intersection contains a type variable, this type variable will be eagerly
914 solved. Once this case is moved, we can clean up obj_get from the Tvar and
915 Tintersection cases *)
917 let (obj_get_ty
, error_prop
) =
918 Errors.try_with_result
920 let (env
, (obj_get_ty
, _tal
)) =
921 Typing_object_get.obj_get
922 ~obj_pos
:(Reason.to_pos
r)
933 (obj_get_ty
, valid_env env
))
934 (fun (obj_get_ty
, _
) error
->
935 (obj_get_ty
, invalid_with (fun () -> Errors.add_error error
)))
938 &&& simplify_subtype ~
subtype_env ~
this_ty obj_get_ty member_ty
))
940 (* Next deal with all locl types *)
941 | LoclType
ty_super ->
942 (match deref
ty_super with
945 | ConstraintType cty
when is_constraint_type_union cty
->
947 | ConstraintType _
->
948 if subtype_env.no_top_bottom
then
953 (match deref lty
with
954 | (_
, Tunion _
) -> default_subtype env
955 | (_
, Terr
) -> valid ()
957 if subtype_env.no_top_bottom
then
961 | (_
, Tvar var_super
) ->
963 | ConstraintType cty
when is_constraint_type_union cty
->
965 | ConstraintType _
-> default ()
967 (match deref
ty_sub with
968 | (_
, (Tunion _
| Terr
)) -> default_subtype env
969 | (_
, Tdynamic
) when subtype_env.treat_dynamic_as_bottom
->
971 (* We want to treat nullable as a union with the same rule as above.
972 * This is only needed for Tvar on right; other cases are dealt with specially as
976 let ty_null = MakeType.null
r in
978 |> simplify_subtype ~
subtype_env ~
this_ty t
ty_super
979 &&& simplify_subtype ~
subtype_env ~
this_ty ty_null ty_super
980 | (_
, Tvar var_sub
) when Ident.equal var_sub var_super
-> valid ()
981 | _
when subtype_env.treat_dynamic_as_bottom
->
982 (env
, TL.Coerce
(ty_sub, ty_super))
984 | (_
, Tintersection tyl
) ->
986 | ConstraintType cty
when is_constraint_type_union cty
->
988 | LoclType lty
when is_union lty
-> default_subtype env
989 (* t <: (t1 & ... & tn)
991 * t <: t1 /\ ... /\ t <: tn
994 List.fold_left tyl ~init
:(env
, TL.valid) ~f
:(fun res
ty_super ->
995 let ty_super = LoclType
ty_super in
996 res
&&& simplify_subtype_i ~
subtype_env ~
this_ty ty_sub ty_super))
997 (* Empty union encodes the bottom type nothing *)
998 | (_
, Tunion
[]) -> default_subtype env
999 (* ty_sub <: union{ty_super'} iff ty_sub <: ty_super' *)
1000 | (_
, Tunion
[ty_super'
]) ->
1001 simplify_subtype_i ~
subtype_env ~
this_ty ty_sub (LoclType
ty_super'
) env
1002 | (_
, Tunion
(_
:: _
as tyl_super
)) ->
1003 let simplify_sub_union env
ty_sub tyl_super
=
1004 (* It's sound to reduce t <: t1 | t2 to (t <: t1) || (t <: t2). But
1005 * not complete e.g. consider (t1 | t3) <: (t1 | t2) | (t2 | t3).
1006 * But we deal with unions on the left first (see case above), so this
1007 * particular situation won't arise.
1008 * TODO: identify under what circumstances this reduction is complete.
1010 let rec try_each tys env
=
1016 match get_node lty
with
1025 let ty = LoclType
ty in
1027 |> simplify_subtype_i ~
subtype_env ~
this_ty ty_sub ty
1030 try_each tyl_super env
1033 | ConstraintType cty
when is_constraint_type_union cty
->
1035 | ConstraintType _
-> simplify_sub_union env
ty_sub tyl_super
1036 | LoclType lty_sub
->
1037 (match deref lty_sub
with
1038 | (_
, (Tunion _
| Terr
| Tvar _
)) -> default_subtype env
1039 | (_
, Tgeneric _
) when Option.is_none
subtype_env.seen_generic_params
->
1041 (* Num is not atomic: it is equivalent to int|float. The rule below relies
1042 * on ty_sub not being a union e.g. consider num <: arraykey | float, so
1043 * we break out num first.
1045 | (r, Tprim
Nast.Tnum
) ->
1046 let ty_float = MakeType.float r and ty_int
= MakeType.int r in
1048 |> simplify_subtype ~
subtype_env ~
this_ty ty_float ty_super
1049 &&& simplify_subtype ~
subtype_env ~
this_ty ty_int
ty_super
1050 (* Likewise, reduce nullable on left to a union *)
1051 | (r, Toption
ty) ->
1052 let ty_null = MakeType.null
r in
1061 if TL.is_unsat p1
then
1072 (env
, TL.conj p1 p2
)
1073 | (_
, Tintersection tyl
)
1074 when let (_
, non_ty_opt
, _
) = find_type_with_exact_negation env tyl
in
1075 Option.is_some non_ty_opt
->
1077 | (_
, Tintersection tyl_sub
) ->
1078 let simplify_super_intersection env tyl_sub
ty_super =
1079 (* It's sound to reduce t1 & t2 <: t to (t1 <: t) || (t2 <: t), but
1084 ~init
:(env
, TL.invalid ~
fail)
1085 ~f
:(fun res
ty_sub ->
1086 let ty_sub = LoclType
ty_sub in
1087 res
||| simplify_subtype_i ~
subtype_env ~
this_ty ty_sub ty_super)
1089 (* Heuristicky logic to decide whether to "break" the intersection
1090 or the union first, based on observing that the following cases often occur:
1091 - A & B <: (A & B) | C
1092 In which case we want to "break" the union on the right first
1093 in order to have the following recursive calls :
1096 - A & (B | C) <: B | C
1097 In which case we want to "break" the intersection on the left first
1098 in order to have the following recursive calls:
1102 if List.exists tyl_super ~f
:(Typing_utils.is_tintersection env
) then
1103 simplify_sub_union env
ty_sub tyl_super
1104 else if List.exists tyl_sub ~f
:(Typing_utils.is_tunion env
) then
1105 simplify_super_intersection env tyl_sub
(LoclType
ty_super)
1107 simplify_sub_union env
ty_sub tyl_super
1108 | _
-> simplify_sub_union env
ty_sub tyl_super
))
1109 | (r_super, Toption arg_ty_super
) ->
1110 let (env
, ety
) = Env.expand_type env arg_ty_super
in
1111 (* Toption(Tnonnull) encodes mixed, which is our top type.
1112 * Everything subtypes mixed *)
1113 if is_nonnull ety
then
1117 | ConstraintType _
-> default_subtype env
1118 | LoclType lty_sub
->
1119 (match (deref lty_sub
, get_node ety
) with
1120 | ((_
, Tnewtype
(name_sub
, _
, _
)), Tnewtype
(name_sup
, _
, _
))
1121 when String.equal name_sup name_sub
->
1122 simplify_subtype ~
subtype_env ~
this_ty lty_sub arg_ty_super env
1123 (* A <: ?B iif A & nonnull <: B
1124 Only apply if B is a type variable or an intersection, to avoid oscillating
1125 forever between this case and the previous one. *)
1126 | ((_
, Tintersection tyl
), (Tintersection _
| Tvar _
))
1127 when let (_
, non_ty_opt
, _
) =
1128 find_type_with_exact_negation env tyl
1130 Option.is_none non_ty_opt
->
1131 let (env
, ty_sub'
) =
1132 Inter.intersect_i env
r_super ty_sub (MakeType.nonnull
r_super)
1134 simplify_subtype_i ~
subtype_env ty_sub'
(LoclType arg_ty_super
) env
1135 (* null is the type of null and is a subtype of any option type. *)
1136 | ((_
, Tprim
Nast.Tnull
), _
) -> valid ()
1137 (* ?ty_sub' <: ?ty_super' iff ty_sub' <: ?ty_super'. Reasoning:
1138 * If ?ty_sub' <: ?ty_super', then from ty_sub' <: ?ty_sub' (widening) and transitivity
1139 * of <: it follows that ty_sub' <: ?ty_super'. Conversely, if ty_sub' <: ?ty_super', then
1140 * by covariance and idempotence of ?, we have ?ty_sub' <: ??ty_sub' <: ?ty_super'.
1141 * Therefore, this step preserves the set of solutions.
1143 | ((_
, Toption
ty_sub'
), _
) ->
1144 simplify_subtype ~
subtype_env ~
this_ty ty_sub'
ty_super env
1145 (* We do not want to decompose Toption for these cases *)
1146 | ((_
, (Tvar _
| Tunion _
| Tintersection _
)), _
) ->
1148 | ((_
, Tgeneric _
), _
)
1149 when Option.is_none
subtype_env.seen_generic_params
->
1150 (* TODO(T69551141) handle type arguments ? *)
1152 (* If t1 <: ?t2 and t1 is an abstract type constrained as t1',
1153 * then t1 <: t2 or t1' <: ?t2. The converse is obviously
1154 * true as well. We can fold the case where t1 is unconstrained
1155 * into the case analysis below.
1157 | ((_
, (Tnewtype _
| Tdependent _
| Tgeneric _
| Tprim
Nast.Tvoid
)), _
)
1159 (* TODO(T69551141) handle type arguments? *)
1161 |> simplify_subtype ~
subtype_env ~
this_ty lty_sub arg_ty_super
1163 (* If ty_sub <: ?ty_super' and ty_sub does not contain null then we
1164 * must also have ty_sub <: ty_super'. The converse follows by
1165 * widening and transitivity. Therefore, this step preserves the set
1169 ( Tdynamic
| Tprim _
| Tnonnull
| Tfun _
| Ttuple _
| Tshape _
1170 | Tobject
| Tclass _
| Tvarray _
| Tdarray _
1171 | Tvarray_or_darray _
| Tany _
| Terr
| Tpu _
1172 | Tpu_type_access _
) ),
1174 simplify_subtype ~
subtype_env ~
this_ty lty_sub arg_ty_super env
)
1176 | (r_super, Tdependent
(d_sup
, bound_sup
)) ->
1177 let (env
, bound_sup
) = Env.expand_type env bound_sup
in
1179 | ConstraintType _
-> default_subtype env
1180 | LoclType
ty_sub ->
1181 (match (deref
ty_sub, get_node bound_sup
) with
1182 | ((_
, Tclass _
), Tclass
((_
, x
), _
, _
))
1183 when is_final_and_not_contravariant env x
->
1184 (* For final class C, there is no difference between `this as X` and `X`,
1185 * and `expr<#n> as X` and `X`.
1186 * But we need to take care with contravariant classes, since we can't
1187 * statically guarantee their runtime type.
1189 simplify_subtype ~
subtype_env ~
this_ty ty_sub bound_sup env
1190 | ((r_sub, Tclass
((_
, y
), _
, _
)), Tclass
(((_
, x
) as id
), _
, tyl_super
))
1193 if String.equal x y
then
1195 let p = Reason.to_pos
r_sub in
1197 ( if equal_dependent_type d_sup
(DTcls x
) then
1198 Errors.exact_class_final id
p
1200 Errors.this_final id
p )
1205 let class_def = Env.get_class env x
in
1206 (match (d_sup
, class_def) with
1207 | (DTthis
, Some class_ty
) ->
1210 List.is_empty
tyl_super
1211 && not
(Partial.should_check_error
(Env.get_mode env
) 4029)
1213 List.map
(Cls.tparams class_ty
) (fun _
->
1214 mk
(r_super, Typing_defs.make_tany
()))
1221 (List.length
(Cls.tparams class_ty
))
1222 (List.length
tyl_super))
1224 invalid_with (fun () ->
1225 Errors.expected_tparam
1226 ~definition_pos
:(Cls.pos class_ty
)
1227 ~use_pos
:(Reason.to_pos
r_super)
1228 (List.length
(Cls.tparams class_ty
))
1229 (Some
subtype_env.on_error
))
1233 type_expansions
= [];
1234 substs
= Subst.make_locl
(Cls.tparams class_ty
) tyl_super;
1235 this_ty = Option.value this_ty ~
default:ty_super;
1237 on_error
= subtype_env.on_error
;
1241 let lower_bounds_super = Cls.lower_bounds_on_this class_ty
in
1242 let rec try_constraints lower_bounds_super env
=
1243 match lower_bounds_super with
1244 | [] -> invalid_with fail
1245 | ty_super :: lower_bounds_super ->
1246 let (env
, ty_super) = Phase.localize ~
ety_env env
ty_super in
1248 |> simplify_subtype ~
subtype_env ~
this_ty ty_sub ty_super
1249 ||| try_constraints lower_bounds_super
1251 try_constraints lower_bounds_super env
1252 | _
-> invalid_with fail)
1253 | ((_
, Tdependent
(d_sub
, bound_sub
)), _
) ->
1254 let this_ty = Option.first_some
this_ty (Some
ty_sub) in
1255 (* Dependent types are identical but bound might be different *)
1256 if equal_dependent_type d_sub d_sup
then
1257 simplify_subtype ~
subtype_env ~
this_ty bound_sub bound_sup env
1259 simplify_subtype ~
subtype_env ~
this_ty bound_sub
ty_super env
1260 | _
-> default_subtype env
))
1261 | (_
, Tgeneric
(name_super
, _tyargs
)) ->
1262 (* TODO(T69551141) handle type arguments *)
1264 | ConstraintType _
-> default_subtype env
1265 (* If subtype and supertype are the same generic parameter, we're done *)
1266 | LoclType
ty_sub ->
1267 (match get_node
ty_sub with
1268 | Tgeneric
(name_sub
, _tyargs
) when String.equal name_sub name_super
->
1270 (* TODO(T69551141) handle type arguments *)
1271 (* When decomposing subtypes for the purpose of adding bounds on generic
1272 * parameters to the context, (so seen_generic_params = None), leave
1273 * subtype so that the bounds get added *)
1279 (match subtype_env.seen_generic_params
with
1280 | None
-> default ()
1282 (* If we've seen this type parameter before then we must have gone
1283 * round a cycle so we fail
1285 if SSet.mem name_super seen
then
1288 let subtype_env = add_seen_generic subtype_env name_super
in
1289 (* Collect all the lower bounds ("super" constraints) on the
1290 * generic parameter, and check ty_sub against each of them in turn
1291 * until one of them succeeds *)
1292 let rec try_bounds tyl env
=
1294 | [] -> default_subtype env
1297 |> simplify_subtype ~
subtype_env ~
this_ty ty_sub ty
1300 (* Turn error into a generic error about the type parameter *)
1303 (Typing_set.elements
(Env.get_lower_bounds env name_super
))
1304 |> if_unsat
invalid)))
1307 | ConstraintType cty
->
1309 match deref_constraint_type cty
with
1310 | (_
, (Thas_member _
| Tdestructure _
)) -> valid ()
1311 | _
-> default_subtype env
1314 (match deref lty
with
1318 ( Tint
| Tbool
| Tfloat
| Tstring
| Tresource
| Tnum
1319 | Tarraykey
| Tnoreturn
| Tatom _
))
1320 | Tnonnull
| Tfun _
| Ttuple _
| Tshape _
| Tobject
| Tclass _
1321 | Tvarray _
| Tdarray _
| Tvarray_or_darray _
| Tpu _
1322 | Tpu_type_access _
) ) ->
1324 | _
-> default_subtype env
))
1327 | LoclType lty
when is_dynamic lty
-> valid ()
1330 default_subtype env
)
1331 | (_
, Tprim prim_ty
) ->
1333 | ConstraintType _
-> default_subtype env
1335 (match (deref lty
, prim_ty
) with
1336 | ((_
, Tprim
(Nast.Tint
| Nast.Tfloat
)), Nast.Tnum
) -> valid ()
1337 | ((_
, Tprim
(Nast.Tatom _
)), Nast.Tstring
) -> valid ()
1338 | ((_
, Tpu
(_
, _
)), Nast.Tstring
) -> valid ()
1339 | ((_
, Tprim
(Nast.Tatom _
| Nast.Tint
| Nast.Tstring
)), Nast.Tarraykey
)
1342 | ((_
, Tpu
(_
, _
)), Nast.Tarraykey
) -> valid ()
1343 | ((_
, Tprim prim_sub
), _
) when Aast.equal_tprim prim_sub prim_ty
->
1345 | ((_
, Toption arg_ty_sub
), Nast.Tnull
) ->
1346 simplify_subtype ~
subtype_env ~
this_ty arg_ty_sub
ty_super env
1347 | (_
, _
) -> default_subtype env
))
1350 | ConstraintType _
-> default_subtype env
1351 (* Any class type is a subtype of object *)
1353 (match get_node lty
with
1357 | _
-> default_subtype env
))
1358 | (r_super, Tany _
) ->
1360 | ConstraintType cty
->
1362 match deref_constraint_type cty
with
1363 | (_
, (TCunion _
| TCintersection _
)) -> default_subtype env
1366 | LoclType
ty_sub ->
1367 (match deref
ty_sub with
1368 | (_
, Tany _
) -> valid ()
1369 | (_
, (Tunion _
| Tintersection _
| Tvar _
)) -> default_subtype env
1370 | _
when subtype_env.no_top_bottom
-> default ()
1371 (* If ty_sub contains other types, e.g. C<T>, make this a subtype assertion on
1372 those inner types and `any`. For example transform the assertion
1378 if say C is covariant.
1381 let ty_super = anyfy env
r_super ty_sub in
1382 simplify_subtype ~
subtype_env ~
this_ty ty_sub ty_super env
))
1383 | (_
, Tpu
(base_super
, (_
, enum_super
))) ->
1385 | ConstraintType _
-> default_subtype env
1387 (match deref lty
with
1388 (* TODO: document contravariance *)
1389 | (_
, Tpu
(base_sub
, (_
, enum_sub
)))
1390 when String.equal enum_sub enum_super
->
1391 simplify_subtype ~
subtype_env ~
this_ty base_super base_sub env
1392 (* Atom vs Tpu: check for membership *)
1393 | (_
, Tprim
(Aast_defs.Tatom atom
))
1396 @@ TUtils.class_get_pu_member env base_super enum_super atom
->
1398 | _
-> default_subtype env
))
1399 | (_
, Tpu_type_access
(msuper
, nsuper
)) ->
1401 | ConstraintType _
-> default_subtype env
1402 | LoclType
ty_sub ->
1403 (match get_node
ty_sub with
1404 | Tpu_type_access
(msub
, nsub
) ->
1406 String.equal
(snd nsub
) (snd nsuper
)
1407 && String.equal
(snd msub
) (snd msuper
)
1411 (* It's not 100% clear if we should use invalid_env directly or
1412 * not. All my attempts a building an error here is always
1413 * caught beforehand *)
1417 | Tintersection _
->
1420 (* TODO: check if err is still needed *)
1422 let reason = get_reason
ty_sub in
1423 if Typing_utils.is_any env
ty_sub then
1426 Errors.pu_typing_not_supported
(Reason.to_pos
reason)
1428 invalid_env_with env
err))
1429 | (r_super, Tfun ft_super
) ->
1431 | ConstraintType _
-> default_subtype env
1433 (match deref lty
with
1434 | (r_sub, Tfun ft_sub
) ->
1435 simplify_subtype_funs
1443 | _
-> default_subtype env
))
1444 | (_
, Ttuple
tyl_super) ->
1446 | ConstraintType _
-> default_subtype env
1447 (* (t1,...,tn) <: (u1,...,un) iff t1<:u1, ... , tn <: un *)
1449 (match get_node lty
with
1451 when Int.equal
(List.length
tyl_super) (List.length tyl_sub
) ->
1453 (fun res
ty_sub ty_super ->
1454 res
&&& simplify_subtype ~
subtype_env ty_sub ty_super)
1458 | _
-> default_subtype env
))
1459 | (r_super, Tshape
(shape_kind_super
, fdm_super
)) ->
1461 * shape_field_type A <: shape_field_type B iff:
1462 * 1. A is no more optional than B
1463 * 2. A's type <: B.type
1465 let simplify_subtype_shape_field
1466 r_sub name res
(sft_sub
, explicit_sub
) (sft_super
, _
) =
1467 match (sft_sub
.sft_optional
, sft_super
.sft_optional
) with
1471 &&& simplify_subtype
1478 |> with_error
(fun () ->
1479 let printable_name =
1480 TUtils.get_printable_shape_field_name name
1482 if explicit_sub
then
1483 Errors.required_field_is_optional
1484 (Reason.to_pos
r_sub)
1485 (Reason.to_pos
r_super)
1487 subtype_env.on_error
1489 Errors.missing_field
1490 (Reason.to_pos
r_sub)
1491 (Reason.to_pos
r_super)
1493 subtype_env.on_error
)
1495 let lookup_shape_field_type name
r shape_kind fdm
=
1496 match ShapeMap.find_opt name fdm
with
1497 | Some sft
-> (sft
, true)
1499 let printable_name = TUtils.get_printable_shape_field_name name
in
1501 match shape_kind
with
1504 (Reason.Rmissing_required_field
(Reason.to_pos
r, printable_name))
1507 (Reason.Rmissing_optional_field
(Reason.to_pos
r, printable_name))
1509 ({ sft_ty; sft_optional
= true }, false)
1512 | ConstraintType _
-> default_subtype env
1514 (match deref lty
with
1515 | (r_sub, Tshape
(Open_shape
, _
))
1516 when equal_shape_kind Closed_shape shape_kind_super
->
1517 invalid_with (fun () ->
1518 Errors.shape_fields_unknown
1519 (Reason.to_pos
r_sub)
1520 (Reason.to_pos
r_super)
1521 subtype_env.on_error
)
1522 | (r_sub, Tshape
(shape_kind_sub
, fdm_sub
)) ->
1525 simplify_subtype_shape_field
1529 (lookup_shape_field_type name
r_sub shape_kind_sub fdm_sub
)
1530 (lookup_shape_field_type
1535 (ShapeSet.of_list
(ShapeMap.keys fdm_sub
@ ShapeMap.keys fdm_super
))
1537 | _
-> default_subtype env
))
1538 | (_
, (Tvarray _
| Tdarray _
| Tvarray_or_darray _
)) ->
1540 | ConstraintType _
-> default_subtype env
1542 (match (get_node lty
, get_node
ty_super) with
1543 | (Tvarray
ty_sub, Tvarray
ty_super) ->
1544 simplify_subtype ~
subtype_env ~
this_ty ty_sub ty_super env
1545 | ( Tvarray_or_darray
(tk_sub
, tv_sub
),
1546 Tvarray_or_darray
(tk_super
, tv_super
) )
1547 | (Tdarray
(tk_sub
, tv_sub
), Tdarray
(tk_super
, tv_super
))
1548 | (Tdarray
(tk_sub
, tv_sub
), Tvarray_or_darray
(tk_super
, tv_super
)) ->
1550 |> simplify_subtype ~
subtype_env ~
this_ty tk_sub tk_super
1551 &&& simplify_subtype ~
subtype_env ~
this_ty tv_sub tv_super
1552 | (Tvarray tv_sub
, Tvarray_or_darray
(tk_super
, tv_super
)) ->
1553 let pos = get_pos lty
in
1554 let tk_sub = MakeType.int (Reason.Ridx_vector
pos) in
1556 |> simplify_subtype ~
subtype_env ~
this_ty tk_sub tk_super
1557 &&& simplify_subtype ~
subtype_env ~
this_ty tv_sub tv_super
1558 | (Tvarray _
, Tdarray _
)
1559 | (Tdarray _
, Tvarray _
)
1560 | (Tvarray_or_darray _
, Tdarray _
)
1561 | (Tvarray_or_darray _
, Tvarray _
) ->
1563 | _
-> default_subtype env
))
1564 | (_
, Tnewtype
(name_super
, tyl_super, _
)) ->
1566 | ConstraintType _
-> default_subtype env
1568 (match deref lty
with
1569 | (_
, Tclass
((_
, name_sub
), _
, _
)) ->
1570 if String.equal name_sub name_super
&& Env.is_enum env name_super
then
1574 | (_
, Tnewtype
(name_sub
, tyl_sub
, _
))
1575 when String.equal name_sub name_super
->
1576 if List.is_empty tyl_sub
then
1578 else if Env.is_enum env name_super
&& Env.is_enum env name_sub
then
1581 let td = Env.get_typedef env name_super
in
1584 | Some
{ td_tparams
; _
} ->
1585 let variance_reifiedl =
1586 List.map td_tparams
(fun t
-> (t
.tp_variance
, t
.tp_reified
))
1588 simplify_subtype_variance
1595 | None
-> invalid ()
1597 | _
-> default_subtype env
))
1598 | (r_super, Tclass
(((_
, class_name
) as x_super
), exact_super
, tyl_super))
1601 | ConstraintType _
-> default_subtype env
1602 | LoclType
ty_sub ->
1603 (match deref
ty_sub with
1604 | (_
, Tnewtype
(enum_name
, _
, _
))
1605 when String.equal enum_name class_name
1606 && equal_exact exact_super Nonexact
1607 && Env.is_enum env enum_name
->
1609 | (_
, Tnewtype
(cid
, _
, _
))
1610 when String.equal class_name
SN.Classes.cHH_BuiltinEnum
1611 && Env.is_enum env cid
->
1612 (match tyl_super with
1614 env
|> simplify_subtype ~
subtype_env ~
this_ty ty_sub ty_super'
1615 | _
-> default_subtype env
)
1616 | (_
, Tnewtype
(enum_name
, _
, _
))
1617 when (String.equal enum_name class_name
&& Env.is_enum env enum_name
)
1618 || String.equal class_name
SN.Classes.cXHPChild
->
1621 ( Tvarray _
| Tdarray _
| Tvarray_or_darray _
1622 | Tprim
Nast.(Tstring
| Tarraykey
| Tint
| Tfloat
| Tnum
) ) )
1623 when String.equal class_name
SN.Classes.cXHPChild
1624 && equal_exact exact_super Nonexact
->
1626 | (_
, Tprim
Nast.Tstring
)
1627 when String.equal class_name
SN.Classes.cStringish
1628 && equal_exact exact_super Nonexact
->
1630 (* Match what's done in unify for non-strict code *)
1632 when not
@@ Partial.should_check_error
(Env.get_mode env
) 4110 ->
1634 | (r_sub, Tclass
(x_sub
, exact_sub
, tyl_sub
)) ->
1635 let (cid_super
, cid_sub
) = (snd x_super
, snd x_sub
) in
1637 match (exact_sub
, exact_super
) with
1638 | (Nonexact
, Exact
) -> false
1641 if String.equal cid_super cid_sub
then
1642 if List.is_empty tyl_sub
&& List.is_empty
tyl_super && exact_match
1646 (* This is side-effecting as it registers a dependency *)
1647 let class_def_sub = Env.get_class env cid_sub
in
1648 (* If class is final then exactness is superfluous *)
1650 match class_def_sub with
1651 | Some tc
-> Cls.final tc
1654 if not
(exact_match || is_final) then
1657 (* We handle the case where a generic A<T> is used as A *)
1660 List.is_empty
tyl_super
1661 && not
(Partial.should_check_error
(Env.get_mode env
) 4101)
1663 List.map tyl_sub
(fun _
->
1664 mk
(r_super, Typing_defs.make_tany
()))
1670 List.is_empty
tyl_sub
1671 && not
(Partial.should_check_error
(Env.get_mode env
) 4101)
1673 List.map
tyl_super (fun _
->
1674 mk
(r_super, Typing_defs.make_tany
()))
1678 if Int.( <> ) (List.length
tyl_sub) (List.length
tyl_super) then
1679 let n_sub = String_utils.soi
(List.length
tyl_sub) in
1680 let n_super = String_utils.soi
(List.length
tyl_super) in
1681 invalid_with (fun () ->
1682 Errors.type_arity_mismatch
1687 subtype_env.on_error
)
1689 let variance_reifiedl =
1690 match class_def_sub with
1692 List.map
tyl_sub (fun _
->
1693 (Ast_defs.Invariant
, Aast.Erased
))
1695 List.map
(Cls.tparams class_sub
) (fun t
->
1696 (t
.tp_variance
, t
.tp_reified
))
1698 (* C<t1, .., tn> <: C<u1, .., un> iff
1699 * t1 <:v1> u1 /\ ... /\ tn <:vn> un
1700 * where vi is the variance of the i'th generic parameter of C,
1701 * and <:v denotes the appropriate direction of subtyping for variance v
1703 simplify_subtype_variance
1710 else if not
exact_match then
1713 let class_def_sub = Env.get_class env cid_sub
in
1714 (match class_def_sub with
1716 (* This should have been caught already in the naming phase *)
1719 (* We handle the case where a generic A<T> is used as A *)
1722 List.is_empty
tyl_sub
1723 && not
(Partial.should_check_error
(Env.get_mode env
) 4029)
1725 List.map
(Cls.tparams class_sub
) (fun _
->
1726 mk
(r_sub, Typing_defs.make_tany
()))
1733 (List.length
(Cls.tparams class_sub
))
1734 (List.length
tyl_sub))
1736 invalid_with (fun () ->
1737 Errors.expected_tparam
1738 ~definition_pos
:(Cls.pos class_sub
)
1739 ~use_pos
:(Reason.to_pos
r_sub)
1740 (List.length
(Cls.tparams class_sub
))
1741 (Some
subtype_env.on_error
))
1745 type_expansions
= [];
1746 substs
= Subst.make_locl
(Cls.tparams class_sub
) tyl_sub;
1747 (* TODO: do we need this? *)
1748 this_ty = Option.value this_ty ~
default:ty_sub;
1751 on_error
= subtype_env.on_error
;
1754 let up_obj = Cls.get_ancestor class_sub cid_super
in
1757 let (env
, up_obj) = Phase.localize ~
ety_env env
up_obj in
1758 simplify_subtype ~
subtype_env ~
this_ty up_obj ty_super env
1761 Ast_defs.(equal_class_kind
(Cls.kind class_sub
) Ctrait
)
1763 equal_class_kind
(Cls.kind class_sub
) Cinterface
)
1765 let rec try_upper_bounds_on_this up_objs env
=
1768 (* It's crucial that we don't lose updates to global_tpenv in env that were
1769 * introduced by PHase.localize. TODO: avoid this requirement *)
1771 | ub_obj_typ
:: up_objs
->
1772 (* a trait is never the runtime type, but it can be used
1773 * as a constraint if it has requirements or where constraints
1774 * for its using classes *)
1775 let (env
, ub_obj_typ
) =
1776 Phase.localize ~
ety_env env ub_obj_typ
1782 (mk
(r_sub, get_node ub_obj_typ
))
1784 ||| try_upper_bounds_on_this up_objs
1786 try_upper_bounds_on_this
1787 (Cls.upper_bounds_on_this class_sub
)
1791 | (r_sub, (Tvarray tv
| Tdarray
(_
, tv
) | Tvarray_or_darray
(_
, tv
))) ->
1792 (match (exact_super
, tyl_super) with
1793 | (Nonexact
, [tv_super
])
1794 when String.equal class_name
SN.Collections.cTraversable
1795 || String.equal class_name
SN.Rx.cTraversable
1796 || String.equal class_name
SN.Collections.cContainer
->
1797 (* vec<tv> <: Traversable<tv_super>
1798 * iff tv <: tv_super
1799 * Likewise for vec<tv> <: Container<tv_super>
1800 * and map<_,tv> <: Traversable<tv_super>
1801 * and map<_,tv> <: Container<tv_super>
1803 simplify_subtype ~
subtype_env ~
this_ty tv tv_super env
1804 | (Nonexact
, [tk_super
; tv_super
])
1805 when String.equal class_name
SN.Collections.cKeyedTraversable
1806 || String.equal class_name
SN.Rx.cKeyedTraversable
1807 || String.equal class_name
SN.Collections.cKeyedContainer
->
1808 (match get_node
ty_sub with
1814 (MakeType.int r_sub)
1816 &&& simplify_subtype ~
subtype_env ~
this_ty tv tv_super
1817 | Tvarray_or_darray
(tk
, _
)
1818 | Tdarray
(tk
, _
) ->
1820 |> simplify_subtype ~
subtype_env ~
this_ty tk tk_super
1821 &&& simplify_subtype ~
subtype_env ~
this_ty tv tv_super
1822 | _
-> default_subtype env
)
1824 when String.equal class_name
SN.Collections.cKeyedTraversable
1825 || String.equal class_name
SN.Rx.cKeyedTraversable
1826 || String.equal class_name
SN.Collections.cKeyedContainer
->
1827 (* All arrays are subtypes of the untyped KeyedContainer / Traversables *)
1829 | (_
, _
) -> default_subtype env
)
1830 | _
-> default_subtype env
)))
1832 and simplify_subtype_variance
1833 ~
(subtype_env : subtype_env)
1835 (variance_reifiedl : (Ast_defs.variance
* Aast.reify_kind
) list
)
1836 (children_tyl
: locl_ty list
)
1837 (super_tyl
: locl_ty list
) : env
-> env
* TL.subtype_prop
=
1839 let simplify_subtype reify_kind
=
1840 (* When doing coercions we treat dynamic as a bottom type. This is generally
1841 correct, except for the case when the generic isn't erased. When a generic is
1842 reified it is enforced as if it is it's own separate class in the runtime. i.e.
1845 class Box<reify T> {}
1846 function box_int(): Box<int> { return new Box<~int>(); }
1848 If is enforced like:
1849 class Box<reify T> {}
1850 class Box_int extends Box<int> {}
1851 class Box_like_int extends Box<~int> {}
1853 function box_int(): Box_int { return new Box_like_int(); }
1855 Thus we cannot push the like type to the outside of generic like we can
1860 if not
Aast.(equal_reify_kind reify_kind Erased
) then
1861 { subtype_env with treat_dynamic_as_bottom
= false }
1865 simplify_subtype ~
subtype_env ~
this_ty:None
1867 let simplify_subtype_variance = simplify_subtype_variance ~
subtype_env in
1868 match (variance_reifiedl, children_tyl
, super_tyl
) with
1873 | ( (variance
, reify_kind
) :: variance_reifiedl,
1875 super
:: superl
) ->
1876 let simplify_subtype = simplify_subtype reify_kind
in
1879 | Ast_defs.Covariant
-> simplify_subtype child super env
1880 | Ast_defs.Contravariant
->
1883 ( Reason.Rcontravariant_generic
(get_reason
super, cid
),
1886 simplify_subtype super child env
1887 | Ast_defs.Invariant
->
1889 mk
(Reason.Rinvariant_generic
(get_reason
super, cid
), get_node
super)
1891 env
|> simplify_subtype child
super'
&&& simplify_subtype super' child
1893 &&& simplify_subtype_variance cid
variance_reifiedl childrenl superl
1895 and simplify_subtype_params
1896 ~
(subtype_env : subtype_env)
1897 ?
(is_method
: bool = false)
1898 ?
(check_params_reactivity
= false)
1899 ?
(check_params_mutability
= false)
1900 (subl
: locl_fun_param list
)
1901 (superl
: locl_fun_param list
)
1902 (variadic_sub_ty
: locl_possibly_enforced_ty
option)
1903 (variadic_super_ty
: locl_possibly_enforced_ty
option)
1905 let simplify_subtype_possibly_enforced =
1906 simplify_subtype_possibly_enforced ~
subtype_env
1908 let simplify_subtype_params = simplify_subtype_params ~
subtype_env in
1909 let simplify_subtype_params_with_variadic =
1910 simplify_subtype_params_with_variadic ~
subtype_env
1912 let simplify_supertype_params_with_variadic =
1913 simplify_supertype_params_with_variadic ~
subtype_env
1915 match (subl
, superl
) with
1916 (* When either list runs out, we still have to typecheck that
1917 the remaining portion sub/super types with the other's variadic.
1920 public function a(int $x = 0, string ... $args) // superl = [int], super_var = string
1924 public function a(string ... $args) // subl = [], sub_var = string
1926 , there should be an error because the first argument will be checked against
1927 int, not string that is, ChildClass::a("hello") would crash,
1928 but ParentClass::a("hello") wouldn't.
1930 Similarly, if the other list is longer, aka
1931 ChildClass extends ParentClass {
1932 public function a(mixed ... $args) // superl = [], super_var = mixed
1936 //subl = [string], sub_var = string
1937 public function a(string $x = 0, string ... $args)
1939 It should also check that string is a subtype of mixed.
1942 (match variadic_super_ty
with
1944 | Some
ty -> simplify_supertype_params_with_variadic superl
ty env
)
1946 (match variadic_sub_ty
with
1948 | Some
ty -> simplify_subtype_params_with_variadic subl
ty env
)
1949 | (sub
:: subl
, super :: superl
) ->
1952 if check_params_reactivity
then
1953 simplify_subtype_fun_params_reactivity ~
subtype_env sub
super
1958 if check_params_mutability
then
1963 (get_fp_mutability sub
)
1965 (get_fp_mutability
super)
1969 let { fp_type
= ty_sub; _
} = sub
in
1970 let { fp_type
= ty_super; _
} = super in
1971 (* Check that the calling conventions of the params are compatible. *)
1973 |> simplify_param_modes ~
subtype_env sub
super
1974 &&& simplify_param_accept_disposable ~
subtype_env sub
super
1977 match (get_fp_mode sub
, get_fp_mode
super) with
1978 | (FPinout
, FPinout
) ->
1979 (* Inout parameters are invariant wrt subtyping for function types. *)
1981 |> simplify_subtype_possibly_enforced ty_super ty_sub
1982 &&& simplify_subtype_possibly_enforced ty_sub ty_super
1983 | _
-> env
|> simplify_subtype_possibly_enforced ty_sub ty_super
1985 &&& simplify_subtype_params
1992 and simplify_subtype_params_with_variadic
1993 ~
(subtype_env : subtype_env)
1994 (subl
: locl_fun_param list
)
1995 (variadic_ty
: locl_possibly_enforced_ty
)
1997 let simplify_subtype_possibly_enforced =
1998 simplify_subtype_possibly_enforced ~
subtype_env
2000 let simplify_subtype_params_with_variadic =
2001 simplify_subtype_params_with_variadic ~
subtype_env
2005 | { fp_type
= sub
; _
} :: subl
->
2007 |> simplify_subtype_possibly_enforced sub variadic_ty
2008 &&& simplify_subtype_params_with_variadic subl variadic_ty
2010 and simplify_supertype_params_with_variadic
2011 ~
(subtype_env : subtype_env)
2012 (superl
: locl_fun_param list
)
2013 (variadic_ty
: locl_possibly_enforced_ty
)
2015 let simplify_subtype_possibly_enforced =
2016 simplify_subtype_possibly_enforced ~
subtype_env
2018 let simplify_supertype_params_with_variadic =
2019 simplify_supertype_params_with_variadic ~
subtype_env
2023 | { fp_type
= super; _
} :: superl
->
2025 |> simplify_subtype_possibly_enforced variadic_ty
super
2026 &&& simplify_supertype_params_with_variadic superl variadic_ty
2028 and simplify_subtype_reactivity
2030 ?
(extra_info
: reactivity_extra_info
option)
2031 ?
(is_call_site
= false)
2033 (r_sub : reactivity
)
2035 (r_super : reactivity
)
2036 (env
: env
) : env
* TL.subtype_prop
=
2039 "This function is " ^
TUtils.reactivity_to_string env
r_super ^
"."
2042 "This function is " ^
TUtils.reactivity_to_string env
r_sub ^
"."
2044 subtype_env.on_error
[(p_super
, msg_super); (p_sub
, msg_sub)]
2046 let ( ||| ) = ( ||| ) ~
fail in
2047 let invalid () = invalid ~
fail env
in
2048 let valid () = valid env
in
2049 let maybe_localize t
=
2052 let ety_env = Phase.env_with_self env
in
2053 let (_
, t
) = Phase.localize ~
ety_env env t
in
2058 Option.bind extra_info
(fun { class_ty = cls
; _
} ->
2059 Option.map cls ~f
:maybe_localize)
2061 (* for method declarations check if condition type for r_super includes
2062 reactive method with a matching name. If yes - then it will act as a guarantee
2063 that derived class will have to redefine the method with a shape required
2064 by condition type (reactivity of redefined method must be subtype of reactivity
2065 of method in interface) *)
2066 let check_condition_type_has_matching_reactive_method env
=
2067 (* function type TSub of method M with arbitrary reactivity in derive class
2068 can be subtype of conditionally reactive function type TSuper of method M
2069 defined in base class when condition type has reactive method M.
2072 public function f(): int;
2075 <<__RxIfImplements(Rx::class)>>
2076 public function f(): int { ... }
2079 public function f(): int { ... }
2081 This should be OK because:
2082 - B does not implement Rx (B::f is not compatible with Rx::f) which means
2083 that calling ($b : B)->f() will not be treated as reactive
2084 - if one of subclasses of B will decide to implement B - they will be forced
2085 to redeclare f which now will shadow B::f. Note that B::f will still be
2086 accessible as parent::f() but will be treated as non-reactive call.
2088 match (r_super, extra_info
) with
2089 | ( ( Pure
(Some condition_type_super
)
2090 | Reactive
(Some condition_type_super
)
2091 | Shallow
(Some condition_type_super
)
2092 | Local
(Some condition_type_super
) ),
2093 Some
{ method_info
= Some
(method_name
, is_static
); _
} ) ->
2095 ConditionTypes.try_get_method_from_condition_type
2097 condition_type_super
2102 (* check that reactivity of interface method (effectively a promised
2103 reactivity of a method in derived class) is a subtype of r_super.
2104 NOTE: we check only for unconditional reactivity since conditional
2105 version does not seems to yield a lot and will requre implementing
2106 cycle detection for condition types *)
2108 | Some
{ ce_type
= (lazy ty); _
} ->
2110 match get_node
ty with
2114 (Pure None
| Reactive None
| Shallow None
| Local None
) as
2120 empty_extra_info with
2121 parent_class_ty
= Some
(DeclTy condition_type_super
);
2124 simplify_subtype_reactivity
2138 match (r_sub, r_super) with
2139 (* anything is a subtype of nonreactive functions *)
2140 | (_
, Nonreactive
) -> valid ()
2141 (* to compare two maybe reactive values we need to unwrap them *)
2142 | (MaybeReactive sub
, MaybeReactive
super) ->
2143 simplify_subtype_reactivity
2152 (* for explicit checks at callsites implicitly unwrap maybereactive value:
2153 function f(<<__AtMostRxAsFunc>> F $f)
2154 f(<<__RxLocal>> () ==> {... })
2155 here parameter will be maybereactive and argument - rxlocal
2157 | (sub
, MaybeReactive
super) when is_call_site
->
2158 simplify_subtype_reactivity
2167 (* if is_call_site is falst ignore maybereactive flavors.
2168 This usually happens during subtype checks for arguments and when target
2169 function is conditionally reactive we'll do the proper check
2170 in typing_reactivity.check_call. *)
2171 | (_
, MaybeReactive _
) when not is_call_site
-> valid ()
2173 class A { function f((function(): int) $f) {} }
2176 function f(<<__AtMostRxAsFunc>> (function(): int) $f);
2178 reactivity for arguments is checked contravariantly *)
2182 function f(<<__AtMostRxAsFunc>> (function(): int) $f) { return $f() } *)
2183 | (RxVar None
, RxVar _
) ->
2185 | (RxVar
(Some sub
), RxVar
(Some
super))
2186 | (sub
, RxVar
(Some
super)) ->
2187 simplify_subtype_reactivity
2196 | (RxVar _
, _
) -> invalid ()
2197 | ( (Local cond_sub
| Shallow cond_sub
| Reactive cond_sub
| Pure cond_sub
),
2199 | ((Shallow cond_sub
| Reactive cond_sub
| Pure cond_sub
), Shallow cond_super
)
2200 | ((Reactive cond_sub
| Pure cond_sub
), Reactive cond_super
)
2201 | (Pure cond_sub
, Pure cond_super
) ->
2203 |> simplify_subtype_param_rx_if_impl
2211 ||| check_condition_type_has_matching_reactive_method
2212 (* call_site specific cases *)
2213 (* shallow can call into local *)
2214 | (Local cond_sub
, Shallow cond_super
) when is_call_site
->
2215 simplify_subtype_param_rx_if_impl
2224 (* local can call into non-reactive *)
2225 | (Nonreactive
, Local _
) when is_call_site
-> valid ()
2226 | _
-> check_condition_type_has_matching_reactive_method env
2228 and should_check_fun_params_reactivity
(ft_super
: locl_fun_type
) =
2229 not
(equal_reactivity ft_super
.ft_reactive Nonreactive
)
2231 (* checks condition described by OnlyRxIfImpl condition on parameter is met *)
2232 and simplify_subtype_param_rx_if_impl
2236 (cond_type_sub
: decl_ty
option)
2237 (declared_type_sub
: locl_ty
option)
2239 (cond_type_super
: decl_ty
option)
2240 (env
: env
) : env
* TL.subtype_prop
=
2242 Option.map
cond_type_sub ~f
:(ConditionTypes.localize_condition_type env
)
2244 let cond_type_super =
2245 Option.map
cond_type_super ~f
:(ConditionTypes.localize_condition_type env
)
2249 TL.invalid ~
fail:(fun () ->
2250 Errors.rx_parameter_condition_mismatch
2251 SN.UserAttributes.uaOnlyRxIfImpl
2254 subtype_env.on_error
) )
2256 match (cond_type_sub, cond_type_super) with
2257 (* no condition types - do nothing *)
2258 | (None
, None
) -> valid env
2259 (* condition type is specified only for super - ok for receiver case (is_param is false)
2261 <<__RxLocal, __OnlyRxIfImpl(Rx1::class)>>
2262 public abstract function condlocalrx(): int;
2264 abstract class B extends A {
2265 // ok to override cond local with local (if condition is not met - method
2266 // in base class is non-reactive )
2267 <<__Override, __RxLocal>>
2268 public function condlocalrx(): int {
2272 for parameters we need to verify that declared type of sub is a subtype of
2273 conditional type for super. Here is an example where this is violated:
2280 public function f(A $a): void {
2284 class C2 extends C1 {
2285 // ERROR: invariant f body is reactive iff $a instanceof RxA can be violated
2286 <<__Rx, __AtMostRxAsArgs>>
2287 public function f(<<__OnlyRxIfImpl(RxA::class)>>A $a): void {
2290 here declared type of sub is A
2291 and cond type of super is RxA
2293 | (None
, Some _
) when not is_param
-> valid env
2294 | (None
, Some
cond_type_super) ->
2296 match declared_type_sub
with
2297 | None
-> invalid ()
2298 | Some declared_type_sub
->
2299 simplify_subtype ~
subtype_env declared_type_sub
cond_type_super env
2301 (* condition types are set for both sub and super types: contravariant check
2303 interface B extends A {}
2304 interface C extends B {}
2307 <<__Rx, __OnlyRxIfImpl(B::class)>>
2308 public function f(): void;
2310 public function g(<<__OnlyRxIfImpl(B::class)>> A $a): void;
2312 interface I2 extends I1 {
2313 // OK since condition in I1::f covers I2::f
2314 <<__Rx, __OnlyRxIfImpl(A::class)>>
2315 public function f(): void;
2316 // OK since condition in I1::g covers I2::g
2318 public function g(<<__OnlyRxIfImpl(A::class)>> A $a): void;
2320 interface I3 extends I1 {
2321 // Error since condition in I1::f is less strict that in I3::f
2322 <<__Rx, __OnlyRxIfImpl(C::class)>>
2323 public function f(): void;
2324 // Error since condition in I1::g is less strict that in I3::g
2326 public function g(<<__OnlyRxIfImpl(C::class)>> A $a): void;
2329 | (Some
cond_type_sub, Some
cond_type_super) ->
2331 simplify_subtype ~
subtype_env cond_type_sub cond_type_super env
2333 simplify_subtype ~
subtype_env cond_type_super cond_type_sub env
2334 (* condition type is set for super type, check if declared type of
2335 subtype is a subtype of condition type
2338 public function f(int $a): void;
2341 <<__Rx, __OnlyRxIfImpl(Rx::class)>>
2342 public function f(T $a): void {
2345 // B <: Rx so B::f is completely reactive
2346 class B extends A<int> implements Rx {
2348 | (Some
cond_type_sub, None
) ->
2352 match declared_type_sub
with
2353 | None
-> invalid ()
2354 | Some declared_type_sub
->
2355 simplify_subtype ~
subtype_env declared_type_sub
cond_type_sub env
2358 (* checks reactivity conditions for function parameters *)
2359 and simplify_subtype_fun_params_reactivity
2360 ~
subtype_env (p_sub
: locl_fun_param
) (p_super
: locl_fun_param
) env
=
2361 match (p_sub
.fp_rx_annotation
, p_super
.fp_rx_annotation
) with
2362 (* no conditions on parameters - do nothing *)
2363 | (None
, None
) -> valid env
2364 (* both parameters are conditioned to be rx function - no need to check anything *)
2365 | (Some Param_rx_var
, Some Param_rx_var
) -> valid env
2366 | (None
, Some Param_rx_var
) ->
2367 (* parameter is conditionally reactive in supertype and missing condition
2368 in subtype - this is ok only if parameter in subtype is reactive
2370 function super((function(): int) $f);
2372 function sub(<<__AtMostRxAsFunc>> (function(): int) $f);
2373 We check if sub <: super. parameters are checked contravariantly
2374 so we need to verify that
2375 (function(): int) $f <: <<__AtMostRxAsFunc>> (function(): int) $f
2377 Suppose this is legal, then this will be allowed (in pseudo-code)
2379 function sub(<<__AtMostRxAsFunc>> (function(): int) $f) {
2380 $f(); // can call function here since it is conditionally reactive
2385 // invoke non-reactive code in reactive context which is bad
2386 $f(() ==> { echo 1; });
2389 It will be safe if parameter in super will be completely reactive,
2390 hence check below *)
2391 let (_
, p_sub_type
) = Env.expand_type env p_sub
.fp_type
.et_type
in
2393 match get_node p_sub_type
with
2394 | Tfun tfun
when not
(equal_reactivity tfun
.ft_reactive Nonreactive
) ->
2398 TL.invalid ~
fail:(fun () ->
2399 Errors.rx_parameter_condition_mismatch
2400 SN.UserAttributes.uaAtMostRxAsFunc
2403 subtype_env.on_error
) )
2404 (* parameter type is not function - error will be reported in different place *)
2407 | (cond_sub
, cond_super
) ->
2410 | Some
(Param_rx_if_impl t
) -> Some t
2413 let cond_type_super =
2414 match cond_super
with
2415 | Some
(Param_rx_if_impl t
) -> Some t
2423 Errors.rx_parameter_condition_mismatch
2424 SN.UserAttributes.uaOnlyRxIfImpl
2427 subtype_env.on_error
);
2430 simplify_subtype_param_rx_if_impl
2435 (Some p_sub
.fp_type
.et_type
)
2440 and simplify_param_modes ~
subtype_env param1 param2 env
=
2441 let { fp_pos
= pos1
; _
} = param1
in
2442 let { fp_pos
= pos2
; _
} = param2
in
2443 match (get_fp_mode param1
, get_fp_mode param2
) with
2444 | (FPnormal
, FPnormal
)
2445 | (FPinout
, FPinout
) ->
2447 | (FPnormal
, FPinout
) ->
2449 ~
fail:(fun () -> Errors.inoutness_mismatch pos2 pos1
subtype_env.on_error
)
2451 | (FPinout
, FPnormal
) ->
2453 ~
fail:(fun () -> Errors.inoutness_mismatch pos1 pos2
subtype_env.on_error
)
2456 and simplify_param_accept_disposable ~
subtype_env param1 param2 env
=
2457 let { fp_pos
= pos1
; _
} = param1
in
2458 let { fp_pos
= pos2
; _
} = param2
in
2459 match (get_fp_accept_disposable param1
, get_fp_accept_disposable param2
) with
2463 Errors.accept_disposable_invariant pos1 pos2
subtype_env.on_error
)
2468 Errors.accept_disposable_invariant pos2 pos1
subtype_env.on_error
)
2470 | (_
, _
) -> valid env
2472 (* Helper function for subtyping on function types: performs all checks that
2473 * don't involve actual types:
2474 * <<__ReturnDisposable>> attribute
2475 * <<__MutableReturn>> attribute
2476 * <<__Rx>> attribute
2477 * <<__Mutable>> attribute
2478 * whether or not the function is a coroutine
2481 and simplify_subtype_funs_attributes
2483 ?
(extra_info : reactivity_extra_info
option)
2485 (ft_sub
: locl_fun_type
)
2486 (r_super : Reason.t
)
2487 (ft_super
: locl_fun_type
)
2489 let p_sub = Reason.to_pos
r_sub in
2490 let p_super = Reason.to_pos
r_super in
2491 let on_error ?code
:_ _
=
2492 Errors.fun_reactivity_mismatch
2494 (TUtils.reactivity_to_string env ft_super
.ft_reactive
)
2496 (TUtils.reactivity_to_string env ft_sub
.ft_reactive
)
2497 subtype_env.on_error
2499 simplify_subtype_reactivity
2500 ~
subtype_env:{ subtype_env with on_error }
2505 ft_super
.ft_reactive
2508 (Bool.equal
(get_ft_is_coroutine ft_sub
) (get_ft_is_coroutine ft_super
))
2510 Errors.coroutinness_mismatch
2511 (get_ft_is_coroutine ft_super
)
2514 subtype_env.on_error)
2517 (get_ft_return_disposable ft_sub
)
2518 (get_ft_return_disposable ft_super
))
2520 Errors.return_disposable_mismatch
2521 (get_ft_return_disposable ft_super
)
2524 subtype_env.on_error)
2525 |> (* it is ok for subclass to return mutably owned value and treat it as immutable -
2526 the fact that value is mutably owned guarantees it has only single reference so
2527 as a result this single reference will be immutable. However if super type
2528 returns mutable value and subtype yields immutable value - this is not safe.
2529 NOTE: error is not reported if child is non-reactive since it does not have
2530 immutability-by-default behavior *)
2533 (get_ft_returns_mutable ft_sub
)
2534 (get_ft_returns_mutable ft_super
)
2535 || (not
(get_ft_returns_mutable ft_super
))
2536 || equal_reactivity ft_sub
.ft_reactive Nonreactive
)
2538 Errors.mutable_return_result_mismatch
2539 (get_ft_returns_mutable ft_super
)
2542 subtype_env.on_error)
2544 ( equal_reactivity ft_super
.ft_reactive Nonreactive
2545 || get_ft_returns_void_to_rx ft_super
2546 || not
(get_ft_returns_void_to_rx ft_sub
) )
2548 (* __ReturnsVoidToRx can be omitted on subtype, in this case using subtype
2549 via reference to supertype in rx context will be ok since result will be
2550 discarded. The opposite is not true:
2553 public function f(): A { return new A(); }
2556 <<__Rx, __Mutable, __ReturnsVoidToRx>>
2557 public function f(): A { return $this; }
2560 <<__Rx, __MutableReturn>>
2561 function f(): A { return new B(); }
2562 $a = HH\Rx\mutable(f());
2563 $a1 = $a->f(); // immutable alias to mutable reference *)
2564 Errors.return_void_to_rx_mismatch
2565 ~pos1_has_attribute
:true
2568 subtype_env.on_error)
2570 (* check mutability only for reactive functions *)
2571 let check_params_mutability =
2572 (not
(equal_reactivity ft_super
.ft_reactive Nonreactive
))
2573 && not
(equal_reactivity ft_sub
.ft_reactive Nonreactive
)
2576 ( if check_params_mutability (* check mutability of receivers *) then
2578 &&& check_mutability
2582 (get_ft_param_mutable ft_super
)
2584 (get_ft_param_mutable ft_sub
)
2588 (arity_min ft_sub
<= arity_min ft_super
)
2589 (fun () -> Errors.fun_too_many_args
p_sub p_super subtype_env.on_error)
2591 match (ft_sub
.ft_arity
, ft_super
.ft_arity
) with
2592 | (Fvariadic
{ fp_name
= None
; _
}, Fvariadic
{ fp_name
= Some _
; _
}) ->
2593 (* The HHVM runtime ignores "..." entirely, but knows about
2594 * "...$args"; for contexts for which the runtime enforces method
2595 * compatibility (currently, inheritance from abstract/interface
2596 * methods), letting "..." override "...$args" would result in method
2597 * compatibility errors at runtime. *)
2600 Errors.fun_variadicity_hh_vs_php56
p_sub p_super subtype_env.on_error)
2602 | (Fstandard
, Fstandard
) ->
2603 let sub_max = List.length ft_sub
.ft_params
in
2604 let super_max = List.length ft_super
.ft_params
in
2605 if sub_max < super_max then
2607 (fun () -> Errors.fun_too_few_args
p_sub p_super subtype_env.on_error)
2614 Errors.fun_unexpected_nonvariadic
p_sub p_super subtype_env.on_error)
2618 and simplify_subtype_possibly_enforced
2619 ~
(subtype_env : subtype_env) et_sub et_super
=
2620 simplify_subtype ~
subtype_env et_sub
.et_type et_super
.et_type
2622 (* This implements basic subtyping on non-generic function types:
2623 * (1) return type behaves covariantly
2624 * (2) parameter types behave contravariantly
2625 * (3) special casing for variadics, and various reactivity and mutability attributes
2627 and simplify_subtype_funs
2628 ~
(subtype_env : subtype_env)
2629 ~
(check_return
: bool)
2630 ?
(extra_info : reactivity_extra_info
option)
2632 (ft_sub
: locl_fun_type
)
2633 (r_super : Reason.t
)
2634 (ft_super
: locl_fun_type
)
2635 env
: env
* TL.subtype_prop
=
2636 let variadic_subtype =
2637 match ft_sub
.ft_arity
with
2638 | Fvariadic
{ fp_type
= var_sub
; _
} -> Some var_sub
2641 let variadic_supertype =
2642 match ft_super
.ft_arity
with
2643 | Fvariadic
{ fp_type
= var_super
; _
} -> Some var_super
2646 let simplify_subtype_possibly_enforced =
2647 simplify_subtype_possibly_enforced ~
subtype_env
2649 let simplify_subtype_params = simplify_subtype_params ~
subtype_env in
2650 (* First apply checks on attributes, coroutine-ness and variadic arity *)
2652 |> simplify_subtype_funs_attributes
2659 &&& (* Now do contravariant subtyping on parameters *)
2661 match (variadic_subtype, variadic_supertype) with
2662 | (Some var_sub
, Some var_super
) ->
2663 simplify_subtype_possibly_enforced var_super var_sub
2667 let check_params_mutability =
2668 (not
(equal_reactivity ft_super
.ft_reactive Nonreactive
))
2669 && not
(equal_reactivity ft_sub
.ft_reactive Nonreactive
)
2674 (Option.map
extra_info (fun i
-> Option.is_some i
.method_info
))
2677 simplify_subtype_params
2679 ~check_params_reactivity
:(should_check_fun_params_reactivity ft_super
)
2680 ~
check_params_mutability
2687 (* Finally do covariant subtryping on return type *)
2688 if check_return
then
2689 simplify_subtype_possibly_enforced ft_sub
.ft_ret ft_super
.ft_ret
2693 (* One of the main entry points to this module *)
2695 ~
subtype_env (env
: env
) (ty_sub : internal_type
) (ty_super : internal_type
)
2697 Env.log_env_change
"sub_type" env
2699 let old_env = env
in
2700 let (env
, success
) =
2701 sub_type_inner ~
subtype_env env ~
this_ty:None
ty_sub ty_super
2708 and sub_type env
(ty_sub : locl_ty
) (ty_super : locl_ty
) on_error =
2710 ~
subtype_env:(make_subtype_env ~treat_dynamic_as_bottom
:false on_error)
2715 (* Add a new upper bound ty on var. Apply transitivity of sutyping,
2716 * so if we already have tyl <: var, then check that for each ty_sub
2717 * in tyl we have ty_sub <: ty.
2719 and add_tyvar_upper_bound_and_close
2720 ~treat_dynamic_as_bottom
(env
, prop
) var
ty on_error =
2721 let upper_bounds_before = Env.get_tyvar_upper_bounds env var
in
2723 Env.add_tyvar_upper_bound_and_update_variances
2724 ~intersect
:(try_intersect_i
env)
2729 let upper_bounds_after = Env.get_tyvar_upper_bounds
env var
in
2730 let added_upper_bounds = ITySet.diff
upper_bounds_after upper_bounds_before in
2731 let lower_bounds = Env.get_tyvar_lower_bounds
env var
in
2734 (fun upper_bound
(env, prop
) ->
2736 Typing_subtype_tconst.make_all_type_consts_equal
2741 ~as_tyvar_with_cnstr
:true
2744 Typing_subtype_pocket_universes.make_all_pu_equal
2751 (fun lower_bound
(env, prop1
) ->
2755 (make_subtype_env ~treat_dynamic_as_bottom
on_error)
2760 (env, TL.conj prop1 prop2
))
2768 (* Add a new lower bound ty on var. Apply transitivity of subtyping
2769 * (so if var <: ty1,...,tyn then assert ty <: tyi for each tyi), using
2770 * simplify_subtype to produce a subtype proposition.
2772 and add_tyvar_lower_bound_and_close
2773 ~treat_dynamic_as_bottom
(env, prop
) var
ty on_error =
2774 let lower_bounds_before = Env.get_tyvar_lower_bounds
env var
in
2776 Env.add_tyvar_lower_bound_and_update_variances
2777 ~union
:(try_union_i
env)
2782 let lower_bounds_after = Env.get_tyvar_lower_bounds
env var
in
2783 let added_lower_bounds = ITySet.diff
lower_bounds_after lower_bounds_before in
2784 let upper_bounds = Env.get_tyvar_upper_bounds
env var
in
2787 (fun lower_bound
(env, prop
) ->
2789 Typing_subtype_tconst.make_all_type_consts_equal
2794 ~as_tyvar_with_cnstr
:false
2797 Typing_subtype_pocket_universes.make_all_pu_equal
2804 (fun upper_bound
(env, prop1
) ->
2808 (make_subtype_env ~treat_dynamic_as_bottom
on_error)
2813 (env, TL.conj prop1 prop2
))
2821 and get_tyvar_opt t
=
2825 match get_node lt
with
2826 | Tvar var
-> Some var
2831 and props_to_env
env remain props
on_error =
2833 | [] -> (env, List.rev remain
)
2836 | TL.Conj props'
-> props_to_env
env remain
(props'
@ props
) on_error
2837 | TL.Disj
(f
, disj_props
) ->
2838 (* For now, just find the first prop in the disjunction that works *)
2839 let rec try_disj disj_props
=
2840 match disj_props
with
2842 (* For now let it fail later when calling
2843 process_simplify_subtype_result on the remaining constraints. *)
2844 props_to_env
env (TL.invalid ~
fail:f
:: remain
) props
on_error
2845 | prop
:: disj_props'
->
2846 let (env'
, other
) = props_to_env
env remain
[prop
] on_error in
2847 if TL.is_unsat
(TL.conj_list other
) then
2848 try_disj disj_props'
2850 props_to_env
env'
(remain
@ other
) props
on_error
2853 | TL.IsSubtype
(ty_sub, ty_super) ->
2855 match (get_tyvar_opt
ty_sub, get_tyvar_opt
ty_super) with
2856 | (Some var_sub
, Some var_super
) ->
2858 add_tyvar_upper_bound_and_close
2859 ~treat_dynamic_as_bottom
:false
2866 add_tyvar_lower_bound_and_close
2867 ~treat_dynamic_as_bottom
:false
2873 props_to_env
env remain
(prop1
:: prop2
:: props
) on_error
2876 add_tyvar_upper_bound_and_close
2877 ~treat_dynamic_as_bottom
:false
2883 props_to_env
env remain
(prop
:: props
) on_error
2886 add_tyvar_lower_bound_and_close
2887 ~treat_dynamic_as_bottom
:false
2893 props_to_env
env remain
(prop
:: props
) on_error
2894 | _
-> props_to_env
env (prop
:: remain
) props
on_error
2896 | TL.Coerce
(ty_sub, ty_super) ->
2898 match (get_node
ty_sub, get_node
ty_super) with
2899 | (Tvar var_sub
, Tvar var_super
) ->
2901 add_tyvar_upper_bound_and_close
2902 ~treat_dynamic_as_bottom
:true
2909 add_tyvar_lower_bound_and_close
2910 ~treat_dynamic_as_bottom
:true
2916 props_to_env
env remain
(prop1
:: prop2
:: props
) on_error
2919 add_tyvar_upper_bound_and_close
2920 ~treat_dynamic_as_bottom
:true
2926 props_to_env
env remain
(prop
:: props
) on_error
2929 add_tyvar_lower_bound_and_close
2930 ~treat_dynamic_as_bottom
:true
2936 props_to_env
env remain
(prop
:: props
) on_error
2937 | _
-> failwith
"Coercion not expected"
2940 (* Move any top-level conjuncts of the form Tvar v <: t or t <: Tvar v to
2941 * the type variable environment. To do: use intersection and union to
2944 and prop_to_env
env prop
on_error =
2945 let (env, props'
) = props_to_env
env [] [prop
] on_error in
2946 (env, TL.conj_list props'
)
2950 ~
(subtype_env : subtype_env)
2951 ~
(this_ty : locl_ty
option)
2952 (ty_sub : internal_type
)
2953 (ty_super : internal_type
) : env * bool =
2957 ~function_name
:"sub_type_inner"
2962 simplify_subtype_i ~
subtype_env ~
this_ty ty_sub ty_super env
2964 let (env, prop
) = prop_to_env
env prop
subtype_env.on_error in
2965 let env = Env.add_subtype_prop
env prop
in
2966 let succeeded = process_simplify_subtype_result prop
in
2969 and is_sub_type_alt_i
2970 ~ignore_generic_params ~no_top_bottom ~treat_dynamic_as_bottom
env ty1 ty2
=
2971 let (this_ty, pos) =
2973 | LoclType ty1
-> (Some ty1
, get_pos ty1
)
2974 | ConstraintType _
-> (None
, Pos.none
)
2980 seen_generic_params
=
2981 ( if ignore_generic_params
then
2986 treat_dynamic_as_bottom
;
2987 on_error = Errors.unify_error_at
pos;
2990 (* It is weird that this can cause errors, but I am wary to discard them.
2991 * Using the generic unify_error to maintain current behavior. *)
2996 if TL.is_valid prop
then
2998 else if TL.is_unsat prop
then
3003 and is_sub_type_alt ~ignore_generic_params ~no_top_bottom
env ty1 ty2
=
3005 ~ignore_generic_params
3011 and is_sub_type
env ty1 ty2
=
3012 let ( = ) = Option.equal
Bool.equal
in
3014 ~ignore_generic_params
:false
3015 ~no_top_bottom
:false
3016 ~treat_dynamic_as_bottom
:false
3022 and is_sub_type_for_coercion
env ty1 ty2
=
3023 let ( = ) = Option.equal
Bool.equal
in
3025 ~ignore_generic_params
:false
3026 ~no_top_bottom
:false
3027 ~treat_dynamic_as_bottom
:true
3033 and is_sub_type_for_union
env ty1 ty2
=
3034 let ( = ) = Option.equal
Bool.equal
in
3036 ~ignore_generic_params
:false
3038 ~treat_dynamic_as_bottom
:false
3044 and is_sub_type_for_union_i
env ty1 ty2
=
3045 let ( = ) = Option.equal
Bool.equal
in
3047 ~ignore_generic_params
:false
3049 ~treat_dynamic_as_bottom
:false
3055 and can_sub_type
env ty1 ty2
=
3056 let ( <> ) a b
= not
(Option.equal
Bool.equal a b
) in
3058 ~ignore_generic_params
:false
3060 ~treat_dynamic_as_bottom
:false
3066 and is_sub_type_ignore_generic_params
env ty1 ty2
=
3067 let ( = ) = Option.equal
Bool.equal
in
3069 ~ignore_generic_params
:true
3071 ~treat_dynamic_as_bottom
:false
3077 and is_sub_type_ignore_generic_params_i
env ty1 ty2
=
3078 let ( = ) = Option.equal
Bool.equal
in
3080 ~ignore_generic_params
:true
3082 ~treat_dynamic_as_bottom
:false
3088 (* Attempt to compute the intersection of a type with an existing list intersection.
3089 * If try_intersect env t [t1;...;tn] = [u1; ...; um]
3090 * then u1&...&um must be the greatest lower bound of t and t1&...&tn wrt subtyping.
3092 * try_intersect nonnull [?C] = [C]
3093 * try_intersect t1 [t2] = [t1] if t1 <: t2
3094 * Note: it's acceptable to return [t;t1;...;tn] but the intention is that
3095 * we simplify (as above) wherever practical.
3096 * It can be assumed that the original list contains no redundancy.
3098 and try_intersect_i
env ty tyl
=
3102 if is_sub_type_ignore_generic_params_i
env ty ty'
then
3103 try_intersect_i
env ty tyl'
3104 else if is_sub_type_ignore_generic_params_i
env ty'
ty then
3107 let nonnull_ty = LoclType
(MakeType.nonnull
(reason ty)) in
3108 let (env, ty) = Env.expand_internal_type
env ty in
3109 let (env, ty'
) = Env.expand_internal_type
env ty'
in
3110 let default () = ty'
:: try_intersect_i
env ty tyl'
in
3111 (match (ty, ty'
) with
3113 when is_sub_type_ignore_generic_params_i
env ty'
nonnull_ty ->
3115 match get_node lty
with
3116 | Toption t
-> try_intersect_i
env (LoclType t
) (ty'
:: tyl'
)
3120 when is_sub_type_ignore_generic_params_i
env ty nonnull_ty ->
3122 match get_node lty
with
3123 | Toption t
-> try_intersect_i
env (LoclType t
) (ty :: tyl'
)
3126 | (_
, _
) -> default ())
3128 and try_intersect
env ty tyl
=
3133 (List.map tyl ~f
:(fun ty -> LoclType
ty)))
3138 "The intersection of two locl type should always be a locl type.")
3140 (* Attempt to compute the union of a type with an existing list union.
3141 * If try_union env t [t1;...;tn] = [u1;...;um]
3142 * then u1|...|um must be the least upper bound of t and t1|...|tn wrt subtyping.
3144 * try_union int [float] = [num]
3145 * try_union t1 [t2] = [t1] if t2 <: t1
3148 * 1. It's acceptable to return [t;t1;...;tn] but the intention is that
3149 * we simplify (as above) wherever practical.
3150 * 2. Do not use Tunion for a syntactic union - the caller can do that.
3151 * 3. It can be assumed that the original list contains no redundancy.
3152 * TODO: there are many more unions to implement yet.
3154 and try_union_i
env ty tyl
=
3158 if is_sub_type_for_union_i
env ty ty'
then
3160 else if is_sub_type_for_union_i
env ty'
ty then
3161 try_union_i
env ty tyl'
3163 let (env, ty) = Env.expand_internal_type
env ty in
3164 let (env, ty'
) = Env.expand_internal_type
env ty'
in
3165 (match (ty, ty'
) with
3166 | (LoclType t1
, LoclType t2
)
3167 when (is_prim
Nast.Tfloat t1
&& is_prim
Nast.Tint t2
)
3168 || (is_prim
Nast.Tint t1
&& is_prim
Nast.Tfloat t2
) ->
3169 let num = LoclType
(MakeType.num (reason ty)) in
3170 try_union_i
env num tyl'
3171 | (_
, _
) -> ty'
:: try_union_i
env ty tyl'
)
3173 and try_union
env ty tyl
=
3175 (try_union_i
env (LoclType
ty) (List.map tyl ~f
:(fun ty -> LoclType
ty)))
3178 | _
-> failwith
"The union of two locl type should always be a locl type.")
3180 let subtype_reactivity
3181 ?
extra_info ?is_call_site
env p_sub r_sub p_super r_super on_error =
3182 let subtype_env = make_subtype_env ~treat_dynamic_as_bottom
:false on_error in
3184 simplify_subtype_reactivity
3194 let (env, prop
) = prop_to_env
env prop
subtype_env.on_error in
3195 ignore
(process_simplify_subtype_result prop
);
3198 let decompose_subtype_add_bound
3199 (env : env) (ty_sub : locl_ty
) (ty_super : locl_ty
) : env =
3200 let (env, ty_super) = Env.expand_type
env ty_super in
3201 let (env, ty_sub) = Env.expand_type
env ty_sub in
3202 match (get_node
ty_sub, get_node
ty_super) with
3203 | (_
, Tany _
) -> env
3204 (* name_sub <: ty_super so add an upper bound on name_sub *)
3205 | (Tgeneric
(name_sub
, _targs
), _
) when not
(phys_equal
ty_sub ty_super) ->
3206 (* TODO(T69551141) handle type arguments *)
3210 ~function_name
:"decompose_subtype_add_bound"
3214 let tys = Env.get_upper_bounds
env name_sub
in
3215 (* Don't add the same type twice! *)
3216 if Typing_set.mem
ty_super tys then
3219 Env.add_upper_bound ~intersect
:(try_intersect
env) env name_sub
ty_super
3220 (* ty_sub <: name_super so add a lower bound on name_super *)
3221 | (_
, Tgeneric
(name_super
, _targs
)) when not
(phys_equal
ty_sub ty_super) ->
3222 (* TODO(T69551141) handle type arguments *)
3226 ~function_name
:"decompose_subtype_add_bound"
3230 let tys = Env.get_lower_bounds
env name_super
in
3231 (* Don't add the same type twice! *)
3232 if Typing_set.mem
ty_sub tys then
3235 Env.add_lower_bound ~union
:(try_union
env) env name_super
ty_sub
3238 (* Given two types that we know are in a subtype relationship
3239 * ty_sub <: ty_super
3240 * add to env.tpenv any bounds on generic type parameters that must
3241 * hold for ty_sub <: ty_super to be valid.
3243 * For example, suppose we know Cov<T> <: Cov<D> for a covariant class Cov.
3244 * Then it must be the case that T <: D so we add an upper bound D to the
3247 * Although some of this code is similar to that for sub_type_inner, its
3248 * purpose is different. sub_type_inner takes two types t and u and makes
3249 * updates to the substitution of type variables (through unification) to
3252 * decompose_subtype takes two types t and u for which t <: u is *assumed* to
3253 * hold, and makes updates to bounds on generic parameters that *necessarily*
3254 * hold in order for t <: u.
3256 let rec decompose_subtype
3260 (ty_super : locl_ty
)
3261 (on_error : Errors.typing_error_callback
) : env =
3265 ~function_name
:"decompose_subtype"
3271 ~
subtype_env:(make_subtype_env ~seen_generic_params
:None
on_error)
3277 decompose_subtype_add_prop
p env prop
3279 and decompose_subtype_add_prop
p env prop
=
3282 List.fold_left ~f
:(decompose_subtype_add_prop
p) ~init
:env props
3283 | TL.Disj
(_
, []) -> Env.mark_inconsistent
env
3284 | TL.Disj
(_
, [prop'
]) -> decompose_subtype_add_prop
p env prop'
3286 Typing_log.log_prop
2 env.function_pos
"decompose_subtype_add_prop" env prop
;
3288 | TL.Coerce _
-> failwith
"Coercions should have been resolved beforehand"
3289 | TL.IsSubtype
(LoclType ty1
, LoclType ty2
) ->
3290 decompose_subtype_add_bound env ty1 ty2
3293 "Subtyping locl types should yield propositions involving locl types only."
3295 (* Decompose a general constraint *)
3296 and decompose_constraint
3299 (ck
: Ast_defs.constraint_kind
)
3301 (ty_super : locl_ty
) : env =
3302 (* constraints are caught based on reason, not error callback. Using unify_error *)
3304 | Ast_defs.Constraint_as
->
3305 decompose_subtype p env ty_sub ty_super (Errors.unify_error_at
p)
3306 | Ast_defs.Constraint_super
->
3307 decompose_subtype p env ty_super ty_sub (Errors.unify_error_at
p)
3308 | Ast_defs.Constraint_eq
->
3310 decompose_subtype p env ty_sub ty_super (Errors.unify_error_at
p)
3312 decompose_subtype p env ty_super ty_sub (Errors.unify_error_at
p)
3314 (* Given a constraint ty1 ck ty2 where ck is AS, SUPER or =,
3315 * add bounds to type parameters in the environment that necessarily
3316 * must hold in order for ty1 ck ty2.
3318 * First, we invoke decompose_constraint to add initial bounds to
3319 * the environment. Then we iterate, decomposing constraints that
3320 * arise through transitivity across bounds.
3322 * For example, suppose that env already contains
3324 * for some covariant class C. Now suppose we add the
3325 * constraint "T2 as C<T3>" i.e. we end up with
3326 * C<T1> <: T2 <: C<T3>
3327 * Then by transitivity we know that T1 <: T3 so we add this to the
3330 * We repeat this process until no further bounds are added to the
3331 * environment, or some limit is reached. (It's possible to construct
3332 * types that expand forever under inheritance.)
3334 let constraint_iteration_limit = 20
3339 (ck
: Ast_defs.constraint_kind
)
3341 (ty_super : locl_ty
) : env =
3345 ~function_name
:"add_constraint"
3349 let oldsize = Env.get_tpenv_size
env in
3350 let env = decompose_constraint
p env ck
ty_sub ty_super in
3351 let ( = ) = Int.equal
in
3352 if Env.get_tpenv_size
env = oldsize then
3355 let rec iter n
env =
3356 if n
> constraint_iteration_limit then
3359 let oldsize = Env.get_tpenv_size
env in
3362 (Env.get_generic_parameters
env)
3366 (Typing_set.elements
(Env.get_lower_bounds
env x
))
3368 ~f
:(fun env ty_sub'
->
3370 (Typing_set.elements
(Env.get_upper_bounds
env x
))
3372 ~f
:(fun env ty_super'
->
3378 (Errors.unify_error_at
p))))
3380 if Int.equal
(Env.get_tpenv_size
env) oldsize then
3387 let add_constraints p env constraints
=
3388 let add_constraint env (ty1
, ck
, ty2
) = add_constraint p env ck ty1 ty2
in
3389 List.fold_left constraints ~f
:add_constraint ~init
:env
3391 let sub_type_with_dynamic_as_bottom
3394 (ty_super : locl_ty
)
3395 (on_error : Errors.typing_error_callback
) : env =
3396 let env_change_log = Env.log_env_change
"coercion" env in
3400 ~function_name
:"coercion"
3404 let old_env = env in
3407 ~
subtype_env:(make_subtype_env ~treat_dynamic_as_bottom
:true on_error)
3413 let (env, prop
) = prop_to_env
env prop
on_error in
3414 let env = Env.add_subtype_prop
env prop
in
3415 let succeeded = process_simplify_subtype_result prop
in
3424 let simplify_subtype_i env ty_sub ty_super ~
on_error =
3426 ~
subtype_env:(make_subtype_env ~no_top_bottom
:true on_error)
3431 (*****************************************************************************)
3433 (*****************************************************************************)
3435 let sub_type_i env ty1 ty2
on_error =
3437 ~
subtype_env:(make_subtype_env ~treat_dynamic_as_bottom
:false on_error)
3443 ~
(check_return
: bool)
3444 ~
(extra_info : reactivity_extra_info
)
3447 (ft_sub
: locl_fun_type
)
3448 (r_super : Reason.t
)
3449 (ft_super
: locl_fun_type
)
3451 let old_env = env in
3453 simplify_subtype_funs
3454 ~
subtype_env:(make_subtype_env on_error)
3463 let (env, prop
) = prop_to_env
env prop
on_error in
3464 let env = Env.add_subtype_prop
env prop
in
3465 let succeeded = process_simplify_subtype_result prop
in
3471 let sub_type_or_fail env ty1 ty2
fail =
3472 sub_type
env ty1 ty2
(fun ?code
:_ _
-> fail ())
3474 let set_fun_refs () =
3475 Typing_utils.sub_type_ref
:= sub_type
;
3476 Typing_utils.sub_type_i_ref
:= sub_type_i;
3477 Typing_utils.sub_type_with_dynamic_as_bottom_ref
:=
3478 sub_type_with_dynamic_as_bottom;
3479 Typing_utils.add_constraint_ref
:= add_constraint;
3480 Typing_utils.is_sub_type_ref
:= is_sub_type
;
3481 Typing_utils.is_sub_type_for_union_ref
:= is_sub_type_for_union
;
3482 Typing_utils.is_sub_type_for_union_i_ref
:= is_sub_type_for_union_i
;
3483 Typing_utils.is_sub_type_ignore_generic_params_ref
:=
3484 is_sub_type_ignore_generic_params
3486 let () = set_fun_refs ()