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 TUtils
= Typing_utils
20 module SN
= Naming_special_names
21 module Phase
= Typing_phase
22 module TL
= Typing_logic
23 module Cls
= Decl_provider.Class
24 module ITySet
= Internal_type_set
25 module MakeType
= Typing_make_type
26 module Partial
= Partial_provider
27 module ShapeMap
= Nast.ShapeMap
28 module ShapeSet
= Ast_defs.ShapeSet
32 seen_generic_params
: SSet.t
option;
34 treat_dynamic_as_bottom
: bool;
35 (* Used with global flag --enable-sound-dynamic-type, allow_subtype_of_dynamic
36 controls whether types that implement dynamic can be subtypes of dynamic *)
37 allow_subtype_of_dynamic
: bool;
38 on_error
: Errors.typing_error_callback
;
41 let empty_seen = Some
SSet.empty
44 ?
(seen_generic_params
= empty_seen)
45 ?
(no_top_bottom
= false)
46 ?
(treat_dynamic_as_bottom
= false)
47 ?
(allow_subtype_of_dynamic
= false)
52 treat_dynamic_as_bottom
;
53 allow_subtype_of_dynamic
;
57 let add_seen_generic subtype_env name
=
58 match subtype_env
.seen_generic_params
with
60 { subtype_env
with seen_generic_params
= Some
(SSet.add name seen
) }
63 type reactivity_extra_info
= {
64 method_info
: (* method_name *) (string * (* is_static *) bool) option;
65 class_ty
: phase_ty
option;
66 parent_class_ty
: phase_ty
option;
69 let empty_extra_info =
70 { method_info
= None
; class_ty
= None
; parent_class_ty
= None
}
72 module ConditionTypes
= struct
73 let try_get_class_for_condition_type (env
: env
) (ty
: decl_ty
) =
74 match TUtils.try_unwrap_class_type ty
with
76 | Some
(_
, ((_
, x
) as sid
), _
) ->
78 match Env.get_class env x
with
80 | Some cls
-> Some
(sid
, cls
)
83 let try_get_method_from_condition_type
84 (env
: env
) (ty
: decl_ty
) (is_static
: bool) (method_name
: string) =
85 match try_get_class_for_condition_type env ty
with
96 let localize_condition_type (env
: env
) (ty
: decl_ty
) : locl_ty
=
97 (* if condition type is generic - we cannot specify type argument in attribute.
98 For cases when we check if containing type is a subtype of condition type
99 if condition type is generic instantiate it with TAny's *)
102 match try_get_class_for_condition_type env
ty with
104 | Some
(((p
, _
) as sid
), cls
) ->
105 let tparams = Cls.tparams cls
in
106 if List.is_empty
tparams then
110 List.map
tparams ~f
:(fun { tp_name
= (p
, x
); _
} ->
111 (* TODO(T69551141) handle type arguments *)
112 MakeType.generic
(Reason.Rwitness p
) x
)
114 let subst = Decl_instantiate.make_subst
tparams [] in
115 let ty = MakeType.apply
(Reason.Rwitness p
) sid
params in
116 Decl_instantiate.instantiate
subst ty
118 let ety_env = Phase.env_with_self env
in
119 let (_
, t
) = Phase.localize ~
ety_env env
ty in
123 | (r
, Toption
ty) -> mk
(r
, Toption
(do_localize ty))
124 | _
-> do_localize ty
127 (* Given a pair of types `ty_sub` and `ty_super` attempt to apply simplifications
128 * and add to the accumulated constraints in `constraints` any necessary and
129 * sufficient [(t1,ck1,u1);...;(tn,ckn,un)] such that
130 * ty_sub <: ty_super iff t1 ck1 u1, ..., tn ckn un
131 * where ck is `as` or `=`. Essentially we are making solution-preserving
132 * simplifications to the subtype assertion, for now, also generating equalities
133 * as well as subtype assertions, for backwards compatibility with use of
136 * If `constraints = []` is returned then the subtype assertion is valid.
138 * If the subtype assertion is unsatisfiable then return `failed = Some f`
139 * where `f` is a `unit-> unit` function that records an error message.
140 * (Sometimes we don't want to call this function e.g. when just checking if
143 * Elide singleton unions, treat invariant generics as both-ways
144 * subtypes, and actually chase hierarchy for extends and implements.
146 * Annoyingly, we need to pass env back too, because Typing_phase.localize
147 * expands type constants. (TODO: work out a better way of handling this)
150 * If assertion is valid (e.g. string <: arraykey) then
151 * result can be the empty list (i.e. nothing is added to the result)
152 * If assertion is unsatisfiable (e.g. arraykey <: string) then
153 * we record this in the failed field of the result.
156 (** Check that a mutability type is a subtype of another mutability type *)
158 ~
(is_receiver
: bool)
161 (mut_sub
: param_mutability
option)
163 (mut_super
: param_mutability
option)
167 | None
-> "immutable"
168 | Some Param_owned_mutable
-> "owned mutable"
169 | Some Param_borrowed_mutable
-> "mutable"
170 | Some Param_maybe_mutable
-> "maybe-mutable"
172 (* maybe-mutable <------immutable
174 <--mutable <-- owned mutable *)
175 match (mut_sub
, mut_super
) with
176 (* immutable is not compatible with mutable *)
177 | (None
, Some
(Param_borrowed_mutable
| Param_owned_mutable
))
178 (* mutable is not compatible with immutable *)
179 | (Some
(Param_borrowed_mutable
| Param_owned_mutable
), None
)
180 (* borrowed mutable is not compatible with owned mutable *)
181 | (Some Param_borrowed_mutable
, Some Param_owned_mutable
)
182 (* maybe-mutable is not compatible with immutable/mutable *)
183 | ( Some Param_maybe_mutable
,
184 (None
| Some
(Param_borrowed_mutable
| Param_owned_mutable
)) ) ->
187 Errors.mutability_mismatch
193 subtype_env
.on_error
)
197 let log_subtype_i ~level ~this_ty ~function_name env ty_sub ty_super
=
199 log_with_level env
"sub" level
(fun () ->
201 [Log_type_i
("ty_sub", ty_sub
); Log_type_i
("ty_super", ty_super
)]
204 Option.value_map this_ty ~default
:types ~f
:(fun ty ->
205 Log_type
("this_ty", ty) :: types)
208 (Reason.to_pos
(reason ty_sub
))
210 [Log_head
(function_name
, types)]))
212 let log_subtype ~this_ty ~function_name env ty_sub ty_super
=
220 let is_final_and_not_contravariant env id
=
221 let class_def = Env.get_class env id
in
223 | Some class_ty
-> TUtils.class_is_final_and_not_contravariant class_ty
226 (** Make all types appearing in the given type a Tany, e.g.
227 - for A<B> return A<_>
228 - for function(A): B return function (_): _
233 inherit Type_mapper.deep_type_mapper
as super
235 method! on_type env _ty
= (env
, mk
(r
, Typing_defs.make_tany
()))
238 let (_
, ty) = super#on_type env
ty in
244 let find_type_with_exact_negation env tyl
=
245 let rec find env tyl acc_tyl
=
247 | [] -> (env
, None
, acc_tyl
)
249 let (env
, non_ty
) = TUtils.non env
(get_reason
ty) ty TUtils.ApproxDown
in
250 let nothing = MakeType.nothing Reason.none
in
251 if ty_equal non_ty
nothing then
252 find env tyl'
(ty :: acc_tyl
)
254 (env
, Some non_ty
, tyl'
@ acc_tyl
)
258 let rec describe_ty_super env
ty =
260 Typing_print.with_blank_tyvars
(fun () ->
261 Typing_print.full_strip_ns_i env
ty)
263 let default () = print ty in
266 let (env
, ty) = Env.expand_type env
ty in
267 (match get_node
ty with
269 let upper_bounds = ITySet.elements
(Env.get_tyvar_upper_bounds env v
) in
270 (* The constraint graph is transitively closed so we can filter tyvars. *)
271 let is_not_tyvar = function
272 | LoclType t
-> not
(is_tyvar t
)
275 let upper_bounds = List.filter
upper_bounds ~f
:is_not_tyvar in
276 (match upper_bounds with
277 | [] -> "some type not known yet"
279 let (locl_tyl
, cstr_tyl
) = List.partition_tf tyl ~f
:is_locl_type
in
281 match (locl_tyl
, cstr_tyl
) with
282 | (_
:: _
, _
:: _
) -> " and "
290 ^
( String.concat ~
sep:" & " (List.map tyl ~f
:print)
291 |> Markdown_lite.md_codify
)
296 (List.map cstr_tyl ~f
:(describe_ty_super env
))
298 "something " ^
locl_descr ^
sep ^
cstr_descr)
299 | Toption
ty when is_tyvar
ty ->
300 "`null` or " ^
describe_ty_super env
(LoclType
ty)
301 | _
-> Markdown_lite.md_codify
(default ()))
302 | ConstraintType
ty ->
303 (match deref_constraint_type
ty with
304 | (_
, Thas_member hm
) ->
309 hm_explicit_targs
= targs
;
314 | None
-> Printf.sprintf
"an object with property `%s`" name
315 | Some _
-> Printf.sprintf
"an object with method `%s`" name
)
316 | (_
, Tdestructure _
) ->
317 Markdown_lite.md_codify
318 (Typing_print.with_blank_tyvars
(fun () ->
319 Typing_print.full_strip_ns_i env
(ConstraintType
ty)))
320 | (_
, TCunion
(lty
, cty
)) ->
323 (describe_ty_super env
(LoclType lty
))
324 (describe_ty_super env
(ConstraintType cty
))
325 | (_
, TCintersection
(lty
, cty
)) ->
328 (describe_ty_super env
(LoclType lty
))
329 (describe_ty_super env
(ConstraintType cty
)))
331 (** Process the constraint proposition. There should only be errors left now,
332 i.e. empty disjunction with error functions we call here. *)
333 let rec process_simplify_subtype_result prop
=
335 | TL.IsSubtype
(_ty1
, _ty2
) ->
336 (* All subtypes should have been resolved *)
337 failwith
"unexpected subtype assertion"
339 (* All coercions should have been resolved *)
340 failwith
"unexpected coercions assertion"
342 (* Evaluates list from left-to-right so preserves order of conjuncts *)
343 List.for_all ~f
:process_simplify_subtype_result props
347 | TL.Disj _
-> failwith
"non-empty disjunction"
350 ~
(subtype_env
: subtype_env
)
351 ?
(this_ty
: locl_ty
option = None
)
354 simplify_subtype_i ~subtype_env ~this_ty
(LoclType ty_sub
) (LoclType ty_super
)
357 ~subtype_env ~
(this_ty
: locl_ty
option) ~fail env ty_sub ty_super
=
358 let default env
= (env
, TL.IsSubtype
(ty_sub
, ty_super
)) in
359 let ( ||| ) = ( ||| ) ~fail
in
360 let (env
, ty_super
) = Env.expand_internal_type env ty_super
in
361 let (env
, ty_sub
) = Env.expand_internal_type env ty_sub
in
362 let default_subtype_inner env ty_sub ty_super
=
363 (* This inner function contains typing rules that are based solely on the subtype
364 * if you need to pattern match on the super type it should NOT be included
368 | ConstraintType cty_sub
->
370 match deref_constraint_type cty_sub
with
371 | (_
, TCunion
(lty_sub
, cty_sub
)) ->
373 |> simplify_subtype_i ~subtype_env
(LoclType lty_sub
) ty_super
374 &&& simplify_subtype_i ~subtype_env
(ConstraintType cty_sub
) ty_super
375 | (_
, TCintersection
(lty_sub
, cty_sub
)) ->
377 |> simplify_subtype_i ~subtype_env
(LoclType lty_sub
) ty_super
378 ||| simplify_subtype_i ~subtype_env
(ConstraintType cty_sub
) ty_super
379 | _
-> invalid ~fail env
381 | LoclType lty_sub
->
385 * t1 <: t /\ ... /\ tn <: t
386 * We want this even if t is a type variable e.g. consider
390 match deref lty_sub
with
392 List.fold_left tyl ~init
:(env
, TL.valid
) ~f
:(fun res ty_sub
->
393 res
&&& simplify_subtype_i ~subtype_env
(LoclType ty_sub
) ty_super
)
395 if subtype_env
.no_top_bottom
then
399 | (_
, Tvar _
) -> default env
400 | (r_sub
, Tintersection tyl
) ->
401 (* A & B <: C iif A <: C | !B *)
402 (match find_type_with_exact_negation env tyl
with
403 | (env
, Some non_ty
, tyl
) ->
404 let (env
, ty_super
) =
405 TUtils.union_i env
(get_reason non_ty
) ty_super non_ty
407 let ty_sub = MakeType.intersection r_sub tyl
in
408 simplify_subtype_i ~subtype_env
(LoclType
ty_sub) ty_super env
410 (* It's sound to reduce t1 & t2 <: t to (t1 <: t) || (t2 <: t), but
415 ~init
:(env
, TL.invalid ~fail
)
416 ~f
:(fun res
ty_sub ->
417 let ty_sub = LoclType
ty_sub in
418 res
||| simplify_subtype_i ~subtype_env ~this_ty
ty_sub ty_super
))
419 | (_
, Tgeneric
(name_sub
, tyargs
)) ->
420 (* TODO(T69551141) handle type arguments. right now, just passin tyargs to
421 Env.get_upper_bounds *)
422 (match subtype_env
.seen_generic_params
with
423 | None
-> default env
425 (* If we've seen this type parameter before then we must have gone
426 * round a cycle so we fail
428 if SSet.mem name_sub seen
then
431 (* If the generic is actually an expression dependent type,
432 we need to update this_ty
436 DependentKind.is_generic_dep_ty name_sub
437 && Option.is_none
this_ty
443 let subtype_env = add_seen_generic subtype_env name_sub
in
444 (* Otherwise, we collect all the upper bounds ("as" constraints) on
445 the generic parameter, and check each of these in turn against
446 ty_super until one of them succeeds
448 let rec try_bounds tyl env
=
451 (* Try an implicit mixed = ?nonnull bound before giving up.
452 This can be useful when checking T <: t, where type t is
453 equivalent to but syntactically different from ?nonnull.
454 E.g., if t is a generic type parameter T with nonnull as
458 Reason.Rimplicit_upper_bound
(get_pos lty_sub
, "?nonnull")
460 let tmixed = LoclType
(MakeType.mixed
r) in
462 |> simplify_subtype_i ~
subtype_env ~
this_ty tmixed ty_super
473 ||| simplify_subtype_i
482 (Env.get_upper_bounds env name_sub tyargs
)))
483 |> (* Turn error into a generic error about the type parameter *)
484 if_unsat
(invalid ~fail
)
485 | (_
, Tdynamic
) when subtype_env.treat_dynamic_as_bottom
-> valid env
486 | (_
, Taccess _
) -> invalid ~fail env
487 | _
-> invalid ~fail env
490 (* We further refine the default subtype case for rules that apply to all
491 * LoclTypes but not to ConstraintTypes
494 | LoclType lty_super
->
496 | ConstraintType _
-> default_subtype_inner env
ty_sub ty_super
497 | LoclType lty_sub
->
499 match deref lty_sub
with
500 | (_
, Tvar _
) when subtype_env.treat_dynamic_as_bottom
->
501 (env
, TL.Coerce
(lty_sub
, lty_super
))
502 | (_
, Tnewtype
(_
, _
, ty)) ->
503 simplify_subtype ~
subtype_env ~
this_ty ty lty_super env
504 | (_
, Tdependent
(_
, ty)) ->
505 let this_ty = Option.first_some
this_ty (Some lty_sub
) in
506 simplify_subtype ~
subtype_env ~
this_ty ty lty_super env
508 if subtype_env.no_top_bottom
then
511 let ty_sub = anyfy env r_sub lty_super
in
512 simplify_subtype ~
subtype_env ~
this_ty ty_sub lty_super env
513 | (r_sub
, Tprim
Nast.Tvoid
) ->
515 Reason.Rimplicit_upper_bound
(Reason.to_pos r_sub
, "?nonnull")
523 |> if_unsat
(invalid ~fail
)
524 | _
-> default_subtype_inner env
ty_sub ty_super
526 | ConstraintType _
-> default_subtype_inner env
ty_sub ty_super
528 (* Attempt to "solve" a subtype assertion ty_sub <: ty_super.
529 * Return a proposition that is equivalent, but simpler, than
530 * the original assertion. Fail with Unsat error_function if
531 * the assertion is unsatisfiable. Some examples:
532 * string <: arraykey ==> True (represented as Conj [])
533 * (For covariant C and a type variable v)
534 * C<string> <: C<v> ==> string <: v
535 * (Assuming that C does *not* implement interface J)
537 * (Assuming we have T <: D in tpenv, and class D implements I)
538 * vec<T> <: vec<I> ==> True
539 * This last one would be left as T <: I if seen_generic_params is None
541 and simplify_subtype_i
542 ~
(subtype_env : subtype_env)
543 ?
(this_ty : locl_ty
option = None
)
544 (ty_sub : internal_type
)
545 (ty_super
: internal_type
)
546 env
: env
* TL.subtype_prop
=
550 ~function_name
:"simplify_subtype"
554 let (env
, ety_super
) = Env.expand_internal_type env ty_super
in
555 let (env
, ety_sub
) = Env.expand_internal_type env
ty_sub in
556 let fail_with_suffix suffix
=
557 let r_super = reason ety_super
in
558 let r_sub = reason ety_sub
in
559 let ty_super_descr = describe_ty_super env ety_super
in
561 Markdown_lite.md_codify
562 (Typing_print.with_blank_tyvars
(fun () ->
563 Typing_print.full_strip_ns_i env ety_sub
))
565 let (ty_super_descr, ty_sub_descr) =
566 if String.equal
ty_super_descr ty_sub_descr then
567 ( "exactly the type " ^
ty_super_descr,
568 "the nonexact type " ^
ty_sub_descr )
570 (ty_super_descr, ty_sub_descr)
572 let left = Reason.to_string
("Expected " ^
ty_super_descr) r_super in
573 let right = Reason.to_string
("But got " ^
ty_sub_descr) r_sub @ suffix
in
574 match (r_super, r_sub) with
575 | (Reason.Rcstr_on_generics
(p
, tparam
), _
)
576 | (_
, Reason.Rcstr_on_generics
(p
, tparam
)) ->
577 Errors.violated_constraint p tparam
left right subtype_env.on_error
579 let claim = List.hd_exn
left in
580 let reasons = List.tl_exn
left @ right in
581 subtype_env.on_error
claim reasons
583 let fail () = fail_with_suffix [] in
584 let ( ||| ) = ( ||| ) ~
fail in
585 (* We *know* that the assertion is unsatisfiable *)
586 let invalid_env env
= invalid ~
fail env
in
587 let invalid_env_with env f
= invalid ~
fail:f env
in
588 (* We don't know whether the assertion is valid or not *)
589 let default env
= (env
, TL.IsSubtype
(ety_sub
, ety_super
)) in
590 let default_subtype env
=
591 default_subtype ~
subtype_env ~
this_ty ~
fail env ety_sub ety_super
594 (* First deal with internal constraint types *)
595 | ConstraintType cty_super
->
596 let using_new_method_call_inference =
597 TypecheckerOptions.method_call_inference
(Env.get_tcopt env
)
600 match deref_constraint_type cty_super
with
601 | (_
, TCintersection
(lty
, cty
)) ->
603 | LoclType t
when is_union t
-> default_subtype env
604 | ConstraintType t
when is_constraint_type_union t
->
608 |> simplify_subtype_i ~
subtype_env ty_sub (LoclType lty
)
609 &&& simplify_subtype_i ~
subtype_env ty_sub (ConstraintType cty
))
610 | (_
, TCunion
(maybe_null
, maybe_has_member
))
611 when using_new_method_call_inference
612 && is_has_member maybe_has_member
614 let (_
, maybe_null
) = Env.expand_type env maybe_null
in
615 is_prim
Aast.Tnull maybe_null
->
616 (* `LHS <: Thas_member(...) | null` is morally a null-safe object access *)
617 let (env
, null_ty
) = Env.expand_type env maybe_null
in
618 let r_null = get_reason null_ty
in
619 let (r, has_member_ty
) = deref_constraint_type maybe_has_member
in
620 (match has_member_ty
with
621 | Thas_member has_member_ty
->
622 simplify_subtype_has_member
630 | _
-> invalid_env env
(* Not possible due to guard in parent match *))
631 | (_
, TCunion
(lty_super
, cty_super
)) ->
633 | ConstraintType cty
when is_constraint_type_union cty
->
635 | ConstraintType _
->
637 |> simplify_subtype_i ~
subtype_env ty_sub (LoclType lty_super
)
638 ||| simplify_subtype_i ~
subtype_env ty_sub (ConstraintType cty_super
)
641 (match deref lty
with
643 let ty_null = MakeType.null
r in
652 &&& simplify_subtype_i ~
subtype_env ~
this_ty (LoclType
ty) ty_super
653 | (_
, (Tintersection _
| Tunion _
| Terr
| Tvar _
)) ->
657 |> simplify_subtype_i ~
subtype_env ty_sub (LoclType lty_super
)
658 ||| simplify_subtype_i
661 (ConstraintType cty_super
)
662 ||| default_subtype))
663 | (r_super, Tdestructure
{ d_required
; d_optional
; d_variadic
; d_kind
})
665 (* List destructuring *)
666 let destructure_array t env
=
667 (* If this is a splat, there must be a variadic box to receive the elements
668 * but for list(...) destructuring this is not required. Example:
670 * function f(int $i): void {}
671 * function g(vec<int> $v): void {
672 * list($a) = $v; // ok (but may throw)
677 | Reason.Runpack_param
(_
, fpos, _
) -> fpos
678 | _
-> Reason.to_pos
r_super
680 match (d_kind
, d_required
, d_variadic
) with
681 | (SplatUnpack
, _
:: _
, _
) ->
682 (* return the env so as not to discard the type variable that might
683 have been created for the Traversable type created below. *)
684 invalid_env_with env
(fun () ->
685 Errors.unpack_array_required_argument
686 (Reason.to_pos
r_super)
688 subtype_env.on_error
)
689 | (SplatUnpack
, [], None
) ->
690 invalid_env_with env
(fun () ->
691 Errors.unpack_array_variadic_argument
692 (Reason.to_pos
r_super)
694 subtype_env.on_error
)
695 | (SplatUnpack
, [], Some _
)
696 | (ListDestructure
, _
, _
) ->
697 List.fold d_required ~init
:(env
, TL.valid
) ~f
:(fun res ty_dest
->
698 res
&&& simplify_subtype ~
subtype_env ~
this_ty t ty_dest
)
700 List.fold d_optional ~init
:(env
, TL.valid
) ~f
:(fun res ty_dest
->
701 res
&&& simplify_subtype ~
subtype_env ~
this_ty t ty_dest
)
703 Option.value_map ~
default:(env
, TL.valid
) d_variadic ~f
:(fun vty
->
704 simplify_subtype ~
subtype_env ~
this_ty t vty env
)
707 let destructure_tuple r ts env
=
708 (* First fill the required elements. If there are insufficient elements, an error is reported.
709 * Fill as many of the optional elements as possible, and the remainder are unioned into the
710 * variadic element. Example:
712 * (float, bool, string, int) <: Tdestructure(#1, opt#2, ...#3) =>
713 * float <: #1 /\ bool <: #2 /\ string <: #3 /\ int <: #3
715 * (float, bool) <: Tdestructure(#1, #2, opt#3) =>
716 * float <: #1 /\ bool <: #2
718 let len_ts = List.length ts
in
719 let len_required = List.length d_required
in
721 let (epos
, fpos, prefix
) =
723 | Reason.Runpack_param
(epos
, fpos, c
) -> (epos
, fpos, c
)
724 | _
-> (Reason.to_pos
r_super, Reason.to_pos
r, 0)
726 invalid_env_with env
(fun () ->
728 (prefix
+ len_required)
732 (Some
subtype_env.on_error
))
734 if len_ts < len_required then
735 arity_error Errors.typing_too_few_args
737 let len_optional = List.length d_optional
in
738 let (ts_required
, remain
) = List.split_n ts
len_required in
739 let (ts_optional
, ts_variadic
) = List.split_n remain
len_optional in
743 ~init
:(env
, TL.valid
)
744 ~f
:(fun res
ty ty_dest
->
745 res
&&& simplify_subtype ~
subtype_env ~
this_ty ty ty_dest
)
747 let len_ts_opt = List.length ts_optional
in
748 let d_optional_part =
749 if len_ts_opt < len_optional then
750 List.take d_optional
len_ts_opt
757 ~init
:(env
, TL.valid
)
758 ~f
:(fun res
ty ty_dest
->
759 res
&&& simplify_subtype ~
subtype_env ~
this_ty ty ty_dest
)
761 match (ts_variadic
, d_variadic
) with
762 | (vars
, Some vty
) ->
763 List.fold vars ~init
:(env
, TL.valid
) ~f
:(fun res
ty ->
764 res
&&& simplify_subtype ~
subtype_env ~
this_ty ty vty
)
765 | ([], None
) -> valid env
767 (* Elements remain but we have nowhere to put them *)
768 arity_error Errors.typing_too_many_args
773 | ConstraintType _
-> default_subtype env
775 (match deref
ty_sub with
776 | (r, Ttuple tyl
) -> env
|> destructure_tuple r tyl
777 | (r, Tclass
((_
, x
), _
, tyl
))
778 when String.equal x
SN.Collections.cPair
->
779 env
|> destructure_tuple r tyl
780 | (_
, Tclass
((_
, x
), _
, [elt_type
]))
781 when String.equal x
SN.Collections.cVector
782 || String.equal x
SN.Collections.cImmVector
783 || String.equal x
SN.Collections.cVec
784 || String.equal x
SN.Collections.cConstVector
->
785 env
|> destructure_array elt_type
786 | (_
, Tvarray elt_type
) -> env
|> destructure_array elt_type
787 | (_
, Tdynamic
) -> env
|> destructure_array ty_sub
788 (* TODO: should remove these any cases *)
790 let any = mk
(r, Typing_defs.make_tany
()) in
791 env
|> destructure_array any
792 | (_
, (Tunion _
| Tintersection _
| Tgeneric _
| Tvar _
)) ->
793 (* TODO(T69551141) handle type arguments of Tgeneric? *)
799 (* Allow splatting of arbitrary Traversables *)
800 let (env
, ty_inner
) =
801 Env.fresh_type env
(Reason.to_pos
r_super)
803 let traversable = MakeType.traversable r_super ty_inner
in
805 |> simplify_subtype ~
subtype_env ~
this_ty ty_sub traversable
806 &&& destructure_array ty_inner
809 Typing_print.with_blank_tyvars
(fun () ->
810 Typing_print.full_strip_ns env
ty_sub)
813 |> if_unsat
@@ fun env
->
814 invalid_env_with env
(fun () ->
815 Errors.invalid_destructure
816 (Reason.to_pos
r_super)
819 subtype_env.on_error
)
822 | (r, Thas_member has_member_ty
) ->
823 simplify_subtype_has_member
831 (* Next deal with all locl types *)
832 | LoclType ty_super
->
833 (match deref ty_super
with
836 | ConstraintType cty
when is_constraint_type_union cty
->
838 | ConstraintType _
->
839 if subtype_env.no_top_bottom
then
844 (match deref lty
with
845 | (_
, Tunion _
) -> default_subtype env
846 | (_
, Terr
) -> valid env
848 if subtype_env.no_top_bottom
then
852 | (_
, Tvar var_super
) ->
854 | ConstraintType cty
when is_constraint_type_union cty
->
856 | ConstraintType _
-> default env
858 (match deref
ty_sub with
859 | (_
, (Tunion _
| Terr
)) -> default_subtype env
860 | (_
, Tdynamic
) when subtype_env.treat_dynamic_as_bottom
->
862 (* We want to treat nullable as a union with the same rule as above.
863 * This is only needed for Tvar on right; other cases are dealt with specially as
867 let (env
, t
) = Env.expand_type env t
in
868 (match get_node t
with
869 (* We special case on `mixed <: Tvar _`, adding the entire `mixed` type
870 as a lower bound. This enables clearer error messages when upper bounds
871 are added to the type variable: transitive closure picks up the
872 entire `mixed` type, and not separately consider `null` and `nonnull` *)
873 | Tnonnull
-> default env
875 let ty_null = MakeType.null
r in
877 |> simplify_subtype ~
subtype_env ~
this_ty t ty_super
878 &&& simplify_subtype ~
subtype_env ~
this_ty ty_null ty_super
)
879 | (_
, Tvar var_sub
) when Ident.equal var_sub var_super
-> valid env
880 | _
when subtype_env.treat_dynamic_as_bottom
->
881 (env
, TL.Coerce
(ty_sub, ty_super
))
883 | (_
, Tintersection tyl
) ->
885 | ConstraintType cty
when is_constraint_type_union cty
->
887 | LoclType lty
when is_union lty
-> default_subtype env
888 (* t <: (t1 & ... & tn)
890 * t <: t1 /\ ... /\ t <: tn
893 List.fold_left tyl ~init
:(env
, TL.valid
) ~f
:(fun res ty_super
->
894 let ty_super = LoclType
ty_super in
895 res
&&& simplify_subtype_i ~
subtype_env ~
this_ty ty_sub ty_super))
896 (* Empty union encodes the bottom type nothing *)
897 | (_
, Tunion
[]) -> default_subtype env
898 (* ty_sub <: union{ty_super'} iff ty_sub <: ty_super' *)
899 | (_
, Tunion
[ty_super'
]) ->
900 simplify_subtype_i ~
subtype_env ~
this_ty ty_sub (LoclType
ty_super'
) env
901 | (_
, Tunion
(_
:: _
as tyl_super
)) ->
902 let simplify_sub_union env
ty_sub tyl_super
=
903 (* It's sound to reduce t <: t1 | t2 to (t <: t1) || (t <: t2). But
904 * not complete e.g. consider (t1 | t3) <: (t1 | t2) | (t2 | t3).
905 * But we deal with unions on the left first (see case above), so this
906 * particular situation won't arise.
907 * TODO: identify under what circumstances this reduction is complete.
909 let rec try_each tys env
=
915 match get_node lty
with
920 | _
-> invalid_env env
922 | _
-> invalid_env env
)
924 let ty = LoclType
ty in
926 |> simplify_subtype_i ~
subtype_env ~
this_ty ty_sub ty
929 try_each tyl_super env
932 | ConstraintType cty
when is_constraint_type_union cty
->
934 | ConstraintType _
-> simplify_sub_union env
ty_sub tyl_super
935 | LoclType lty_sub
->
936 (match deref lty_sub
with
937 | (_
, (Tunion _
| Terr
| Tvar _
)) -> default_subtype env
938 | (_
, Tgeneric _
) when Option.is_none
subtype_env.seen_generic_params
->
940 (* Num is not atomic: it is equivalent to int|float. The rule below relies
941 * on ty_sub not being a union e.g. consider num <: arraykey | float, so
942 * we break out num first.
944 | (r, Tprim
Nast.Tnum
) ->
945 let ty_float = MakeType.float r and ty_int
= MakeType.int r in
947 |> simplify_subtype ~
subtype_env ~
this_ty ty_float ty_super
948 &&& simplify_subtype ~
subtype_env ~
this_ty ty_int
ty_super
949 (* Likewise, reduce nullable on left to a union *)
951 let ty_null = MakeType.null
r in
960 &&& simplify_subtype_i ~
subtype_env ~
this_ty (LoclType
ty) ety_super
961 | (_
, Tintersection tyl
)
962 when let (_
, non_ty_opt
, _
) = find_type_with_exact_negation env tyl
in
963 Option.is_some non_ty_opt
->
965 | (_
, Tintersection tyl_sub
) ->
966 let simplify_super_intersection env tyl_sub
ty_super =
967 (* It's sound to reduce t1 & t2 <: t to (t1 <: t) || (t2 <: t), but
972 ~init
:(env
, TL.invalid ~
fail)
973 ~f
:(fun res
ty_sub ->
974 let ty_sub = LoclType
ty_sub in
975 res
||| simplify_subtype_i ~
subtype_env ~
this_ty ty_sub ty_super)
977 (* Heuristicky logic to decide whether to "break" the intersection
978 or the union first, based on observing that the following cases often occur:
979 - A & B <: (A & B) | C
980 In which case we want to "break" the union on the right first
981 in order to have the following recursive calls :
984 - A & (B | C) <: B | C
985 In which case we want to "break" the intersection on the left first
986 in order to have the following recursive calls:
990 if List.exists tyl_super ~f
:(Typing_utils.is_tintersection env
) then
991 simplify_sub_union env
ty_sub tyl_super
992 else if List.exists tyl_sub ~f
:(Typing_utils.is_tunion env
) then
993 simplify_super_intersection env tyl_sub
(LoclType
ty_super)
995 simplify_sub_union env
ty_sub tyl_super
996 | _
-> simplify_sub_union env
ty_sub tyl_super
))
997 | (r_super, Toption arg_ty_super
) ->
998 let (env
, ety
) = Env.expand_type env arg_ty_super
in
999 (* Toption(Tnonnull) encodes mixed, which is our top type.
1000 * Everything subtypes mixed *)
1001 if is_nonnull ety
then
1005 | ConstraintType _
-> default_subtype env
1006 | LoclType lty_sub
->
1007 (match (deref lty_sub
, get_node ety
) with
1008 | ((_
, Tnewtype
(name_sub
, _
, _
)), Tnewtype
(name_sup
, _
, _
))
1009 when String.equal name_sup name_sub
->
1010 simplify_subtype ~
subtype_env ~
this_ty lty_sub arg_ty_super env
1011 (* A <: ?B iif A & nonnull <: B
1012 Only apply if B is a type variable or an intersection, to avoid oscillating
1013 forever between this case and the previous one. *)
1014 | ((_
, Tintersection tyl
), (Tintersection _
| Tvar _
))
1015 when let (_
, non_ty_opt
, _
) =
1016 find_type_with_exact_negation env tyl
1018 Option.is_none non_ty_opt
->
1019 let (env
, ty_sub'
) =
1020 Inter.intersect_i env
r_super ty_sub (MakeType.nonnull
r_super)
1022 simplify_subtype_i ~
subtype_env ty_sub'
(LoclType arg_ty_super
) env
1023 (* null is the type of null and is a subtype of any option type. *)
1024 | ((_
, Tprim
Nast.Tnull
), _
) -> valid env
1025 (* ?ty_sub' <: ?ty_super' iff ty_sub' <: ?ty_super'. Reasoning:
1026 * If ?ty_sub' <: ?ty_super', then from ty_sub' <: ?ty_sub' (widening) and transitivity
1027 * of <: it follows that ty_sub' <: ?ty_super'. Conversely, if ty_sub' <: ?ty_super', then
1028 * by covariance and idempotence of ?, we have ?ty_sub' <: ??ty_sub' <: ?ty_super'.
1029 * Therefore, this step preserves the set of solutions.
1031 | ((_
, Toption
ty_sub'
), _
) ->
1032 simplify_subtype ~
subtype_env ~
this_ty ty_sub'
ty_super env
1033 (* We do not want to decompose Toption for these cases *)
1034 | ((_
, (Tvar _
| Tunion _
| Tintersection _
)), _
) ->
1036 | ((_
, Tgeneric _
), _
)
1037 when Option.is_none
subtype_env.seen_generic_params
->
1038 (* TODO(T69551141) handle type arguments ? *)
1040 (* If t1 <: ?t2 and t1 is an abstract type constrained as t1',
1041 * then t1 <: t2 or t1' <: ?t2. The converse is obviously
1042 * true as well. We can fold the case where t1 is unconstrained
1043 * into the case analysis below.
1045 | ((_
, (Tnewtype _
| Tdependent _
| Tgeneric _
| Tprim
Nast.Tvoid
)), _
)
1047 (* TODO(T69551141) handle type arguments? *)
1049 |> simplify_subtype ~
subtype_env ~
this_ty lty_sub arg_ty_super
1051 (* If ty_sub <: ?ty_super' and ty_sub does not contain null then we
1052 * must also have ty_sub <: ty_super'. The converse follows by
1053 * widening and transitivity. Therefore, this step preserves the set
1056 | ((_
, Tunapplied_alias _
), _
) ->
1057 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
1059 ( Tdynamic
| Tprim _
| Tnonnull
| Tfun _
| Ttuple _
| Tshape _
1060 | Tobject
| Tclass _
| Tvarray _
| Tdarray _
1061 | Tvarray_or_darray _
| Tany _
| Terr
| Taccess _
) ),
1063 simplify_subtype ~
subtype_env ~
this_ty lty_sub arg_ty_super env
)
1065 | (r_super, Tdependent
(d_sup
, bound_sup
)) ->
1066 let (env
, bound_sup
) = Env.expand_type env bound_sup
in
1068 | ConstraintType _
-> default_subtype env
1069 | LoclType
ty_sub ->
1070 (match (deref
ty_sub, get_node bound_sup
) with
1071 | ((_
, Tclass _
), Tclass
((_
, x
), _
, _
))
1072 when is_final_and_not_contravariant env x
->
1073 (* For final class C, there is no difference between `this as X` and `X`,
1074 * and `expr<#n> as X` and `X`.
1075 * But we need to take care with contravariant classes, since we can't
1076 * statically guarantee their runtime type.
1078 simplify_subtype ~
subtype_env ~
this_ty ty_sub bound_sup env
1079 | ((r_sub, Tclass
((_
, y
), _
, _
)), Tclass
(((_
, x
) as id
), _
, tyl_super
))
1082 if String.equal x y
then
1084 let p = Reason.to_pos
r_sub in
1085 fail_with_suffix (Errors.this_final id
p)
1090 let class_def = Env.get_class env x
in
1091 (match (d_sup
, class_def) with
1092 | (DTthis
, Some class_ty
) ->
1093 let tolerate_wrong_arity =
1094 not
(Partial.should_check_error
(Env.get_mode env
) 4029)
1097 if List.is_empty
tyl_super && tolerate_wrong_arity then
1098 List.map
(Cls.tparams class_ty
) (fun _
->
1099 mk
(r_super, Typing_defs.make_tany
()))
1105 type_expansions
= [];
1107 TUtils.make_locl_subst_for_class_tparams class_ty
tyl_super;
1108 this_ty = Option.value this_ty ~
default:ty_super;
1110 on_error
= subtype_env.on_error
;
1114 let lower_bounds_super = Cls.lower_bounds_on_this class_ty
in
1115 let rec try_constraints lower_bounds_super env
=
1116 match lower_bounds_super with
1117 | [] -> invalid_env_with env
fail
1118 | ty_super :: lower_bounds_super ->
1119 let (env
, ty_super) = Phase.localize ~
ety_env env
ty_super in
1121 |> simplify_subtype ~
subtype_env ~
this_ty ty_sub ty_super
1122 ||| try_constraints lower_bounds_super
1124 try_constraints lower_bounds_super env
1125 | _
-> invalid_env_with env
fail)
1126 | ((_
, Tdependent
(d_sub
, bound_sub
)), _
) ->
1127 let this_ty = Option.first_some
this_ty (Some
ty_sub) in
1128 (* Dependent types are identical but bound might be different *)
1129 if equal_dependent_type d_sub d_sup
then
1130 simplify_subtype ~
subtype_env ~
this_ty bound_sub bound_sup env
1132 simplify_subtype ~
subtype_env ~
this_ty bound_sub
ty_super env
1133 | _
-> default_subtype env
))
1134 | (_
, Taccess _
) -> invalid_env env
1135 | (_
, Tgeneric
(name_super
, tyargs_super
)) ->
1136 (* TODO(T69551141) handle type arguments. Right now, only passing tyargs_super to
1137 Env.get_lower_bounds *)
1139 | ConstraintType _
-> default_subtype env
1140 (* If subtype and supertype are the same generic parameter, we're done *)
1141 | LoclType
ty_sub ->
1142 (match get_node
ty_sub with
1143 | Tgeneric
(name_sub
, tyargs_sub
) when String.equal name_sub name_super
1145 if List.is_empty tyargs_super
then
1148 (* TODO(T69931993) Type parameter env must carry variance information *)
1149 let variance_reifiedl =
1150 List.map tyargs_sub
(fun _
-> (Ast_defs.Invariant
, Aast.Erased
))
1152 simplify_subtype_variance
1159 (* When decomposing subtypes for the purpose of adding bounds on generic
1160 * parameters to the context, (so seen_generic_params = None), leave
1161 * subtype so that the bounds get added *)
1167 (match subtype_env.seen_generic_params
with
1168 | None
-> default env
1170 (* If we've seen this type parameter before then we must have gone
1171 * round a cycle so we fail
1173 if SSet.mem name_super seen
then
1176 let subtype_env = add_seen_generic subtype_env name_super
in
1177 (* Collect all the lower bounds ("super" constraints) on the
1178 * generic parameter, and check ty_sub against each of them in turn
1179 * until one of them succeeds *)
1180 let rec try_bounds tyl env
=
1182 | [] -> default_subtype env
1185 |> simplify_subtype ~
subtype_env ~
this_ty ty_sub ty
1188 (* Turn error into a generic error about the type parameter *)
1191 (Typing_set.elements
1192 (Env.get_lower_bounds env name_super tyargs_super
))
1193 |> if_unsat
invalid_env)))
1196 | ConstraintType cty
->
1198 match deref_constraint_type cty
with
1199 | (_
, (Thas_member _
| Tdestructure _
)) -> valid env
1200 | _
-> default_subtype env
1203 (match deref lty
with
1207 ( Tint
| Tbool
| Tfloat
| Tstring
| Tresource
| Tnum
1208 | Tarraykey
| Tnoreturn
))
1209 | Tnonnull
| Tfun _
| Ttuple _
| Tshape _
| Tobject
| Tclass _
1210 | Tvarray _
| Tdarray _
| Tvarray_or_darray _
| Taccess _
) ) ->
1212 | _
-> default_subtype env
))
1214 when TypecheckerOptions.enable_sound_dynamic env
.genv
.tcopt
1215 && subtype_env.allow_subtype_of_dynamic
->
1217 | ConstraintType _cty
->
1220 | LoclType lty_sub
->
1221 (match deref lty_sub
with
1228 ( Tnull
| Tint
| Tbool
| Tfloat
| Tstring
| Tnum
| Tarraykey
1231 | (_
, Tprim
Aast_defs.(Tresource
| Tnoreturn
))
1234 | (_
, Tshape
(Open_shape
, _
))
1236 | (_
, Tunapplied_alias _
)
1242 | (_
, Tintersection _
)
1243 | (_
, Tgeneric _
) ->
1246 | (_
, Tdarray
(_
, ty))
1248 | (_
, Tvarray_or_darray
(_
, ty)) ->
1249 simplify_subtype ~
subtype_env ty ty_super env
1250 | (_
, Ttuple tyl
) ->
1252 ~init
:(env
, TL.valid
)
1253 ~f
:(fun res
ty_sub ->
1254 res
&&& simplify_subtype ~
subtype_env ty_sub ty_super)
1256 | (_
, Tshape
(Closed_shape
, sftl
)) ->
1258 ~init
:(env
, TL.valid
)
1260 res
&&& simplify_subtype ~
subtype_env sft
.sft_ty
ty_super)
1261 (Nast.ShapeMap.values sftl
)
1262 | (_
, Tclass
((_
, class_id
), _
, tyargs
)) ->
1263 let class_def_sub = Typing_env.get_class env class_id
in
1264 (match class_def_sub with
1266 (* This should have been caught already in the naming phase *)
1269 if Cls.get_implements_dynamic class_sub
then
1271 else if String.equal
(Cls.name class_sub
) SN.Collections.cVec
then
1273 | [tyarg
] -> simplify_subtype ~
subtype_env tyarg
ty_super env
1275 (* This ill-formed type should have been caught earlier *)
1278 default_subtype env
)))
1281 | LoclType lty
when is_dynamic lty
-> valid env
1284 default_subtype env
)
1285 | (_
, Tprim prim_ty
) ->
1287 | ConstraintType _
-> default_subtype env
1289 (match (deref lty
, prim_ty
) with
1290 | ((_
, Tprim
(Nast.Tint
| Nast.Tfloat
)), Nast.Tnum
) -> valid env
1291 | ((_
, Tprim
(Nast.Tint
| Nast.Tstring
)), Nast.Tarraykey
) -> valid env
1292 | ((_
, Tprim prim_sub
), _
) when Aast.equal_tprim prim_sub prim_ty
->
1294 | ((_
, Toption arg_ty_sub
), Nast.Tnull
) ->
1295 simplify_subtype ~
subtype_env ~
this_ty arg_ty_sub
ty_super env
1296 | (_
, _
) -> default_subtype env
))
1299 | ConstraintType _
-> default_subtype env
1300 (* Any class type is a subtype of object *)
1302 (match get_node lty
with
1306 | _
-> default_subtype env
))
1307 | (r_super, Tany _
) ->
1309 | ConstraintType cty
->
1311 match deref_constraint_type cty
with
1312 | (_
, (TCunion _
| TCintersection _
)) -> default_subtype env
1315 | LoclType
ty_sub ->
1316 (match deref
ty_sub with
1317 | (_
, Tany _
) -> valid env
1318 | (_
, (Tunion _
| Tintersection _
| Tvar _
)) -> default_subtype env
1319 | _
when subtype_env.no_top_bottom
-> default env
1320 (* If ty_sub contains other types, e.g. C<T>, make this a subtype assertion on
1321 those inner types and `any`. For example transform the assertion
1327 if say C is covariant.
1330 let ty_super = anyfy env
r_super ty_sub in
1331 simplify_subtype ~
subtype_env ~
this_ty ty_sub ty_super env
))
1332 | (r_super, Tfun ft_super
) ->
1334 | ConstraintType _
-> default_subtype env
1336 (match deref lty
with
1337 | (r_sub, Tfun ft_sub
) ->
1338 simplify_subtype_funs
1346 | _
-> default_subtype env
))
1347 | (_
, Ttuple
tyl_super) ->
1349 | ConstraintType _
-> default_subtype env
1350 (* (t1,...,tn) <: (u1,...,un) iff t1<:u1, ... , tn <: un *)
1352 (match get_node lty
with
1354 when Int.equal
(List.length
tyl_super) (List.length tyl_sub
) ->
1356 (fun res
ty_sub ty_super ->
1357 res
&&& simplify_subtype ~
subtype_env ty_sub ty_super)
1361 | _
-> default_subtype env
))
1362 | (r_super, Tshape
(shape_kind_super
, fdm_super
)) ->
1364 | ConstraintType _
-> default_subtype env
1366 (match deref lty
with
1367 | (r_sub, Tshape
(shape_kind_sub
, fdm_sub
)) ->
1368 simplify_subtype_shape
1372 (r_sub, shape_kind_sub
, fdm_sub
)
1373 (r_super, shape_kind_super
, fdm_super
)
1374 | _
-> default_subtype env
))
1375 | (_
, (Tvarray _
| Tdarray _
| Tvarray_or_darray _
)) ->
1377 | ConstraintType _
-> default_subtype env
1379 (match (get_node lty
, get_node
ty_super) with
1380 | (Tvarray
ty_sub, Tvarray
ty_super) ->
1381 simplify_subtype ~
subtype_env ~
this_ty ty_sub ty_super env
1382 | ( Tvarray_or_darray
(tk_sub
, tv_sub
),
1383 Tvarray_or_darray
(tk_super
, tv_super
) )
1384 | (Tdarray
(tk_sub
, tv_sub
), Tdarray
(tk_super
, tv_super
))
1385 | (Tdarray
(tk_sub
, tv_sub
), Tvarray_or_darray
(tk_super
, tv_super
)) ->
1387 |> simplify_subtype ~
subtype_env ~
this_ty tk_sub tk_super
1388 &&& simplify_subtype ~
subtype_env ~
this_ty tv_sub tv_super
1389 | (Tvarray tv_sub
, Tvarray_or_darray
(tk_super
, tv_super
)) ->
1390 let pos = get_pos lty
in
1391 let tk_sub = MakeType.int (Reason.Ridx_vector
pos) in
1393 |> simplify_subtype ~
subtype_env ~
this_ty tk_sub tk_super
1394 &&& simplify_subtype ~
subtype_env ~
this_ty tv_sub tv_super
1395 | (Tvarray _
, Tdarray _
)
1396 | (Tdarray _
, Tvarray _
)
1397 | (Tvarray_or_darray _
, Tdarray _
)
1398 | (Tvarray_or_darray _
, Tvarray _
) ->
1400 | _
-> default_subtype env
))
1401 | (_
, Tnewtype
(name_super
, tyl_super, _
)) ->
1403 | ConstraintType _
-> default_subtype env
1405 (match deref lty
with
1406 | (_
, Tclass
((_
, name_sub
), _
, _
)) ->
1407 if String.equal name_sub name_super
&& Env.is_enum env name_super
then
1411 | (_
, Tnewtype
(name_sub
, tyl_sub
, _
))
1412 when String.equal name_sub name_super
->
1413 if List.is_empty tyl_sub
then
1415 else if Env.is_enum env name_super
&& Env.is_enum env name_sub
then
1418 let td = Env.get_typedef env name_super
in
1421 | Some
{ td_tparams
; _
} ->
1422 let variance_reifiedl =
1423 List.map td_tparams
(fun t
-> (t
.tp_variance
, t
.tp_reified
))
1425 simplify_subtype_variance
1432 | None
-> invalid_env env
1434 | _
-> default_subtype env
))
1435 | (_
, Tunapplied_alias n_sup
) ->
1437 | ConstraintType _
-> default_subtype env
1439 (match deref lty
with
1440 | (_
, Tunapplied_alias n_sub
) when String.equal n_sub n_sup
-> valid env
1441 | _
-> default_subtype env
))
1442 | (r_super, Tclass
(((_
, class_name
) as x_super
), exact_super
, tyl_super))
1445 | ConstraintType _
-> default_subtype env
1446 | LoclType
ty_sub ->
1447 (match deref
ty_sub with
1448 | (_
, Tnewtype
(enum_name
, _
, _
))
1449 when String.equal enum_name class_name
1450 && equal_exact exact_super Nonexact
1451 && Env.is_enum env enum_name
->
1453 | (_
, Tnewtype
(cid
, _
, _
))
1454 when String.equal class_name
SN.Classes.cHH_BuiltinEnum
1455 && Env.is_enum env cid
->
1456 (match tyl_super with
1458 env
|> simplify_subtype ~
subtype_env ~
this_ty ty_sub ty_super'
1459 | _
-> default_subtype env
)
1460 | (_
, Tnewtype
(enum_name
, _
, _
))
1461 when (String.equal enum_name class_name
&& Env.is_enum env enum_name
)
1462 || String.equal class_name
SN.Classes.cXHPChild
->
1465 ( Tvarray _
| Tdarray _
| Tvarray_or_darray _
1466 | Tprim
Nast.(Tstring
| Tarraykey
| Tint
| Tfloat
| Tnum
) ) )
1467 when String.equal class_name
SN.Classes.cXHPChild
1468 && equal_exact exact_super Nonexact
->
1470 | (_
, Tprim
Nast.Tstring
)
1471 when String.equal class_name
SN.Classes.cStringish
1472 && equal_exact exact_super Nonexact
->
1474 (* Match what's done in unify for non-strict code *)
1476 when not
@@ Partial.should_check_error
(Env.get_mode env
) 4110 ->
1478 | (r_sub, Tclass
(x_sub
, exact_sub
, tyl_sub
)) ->
1479 let (cid_super
, cid_sub
) = (snd x_super
, snd x_sub
) in
1481 match (exact_sub
, exact_super
) with
1482 | (Nonexact
, Exact
) -> false
1485 if String.equal cid_super cid_sub
then
1486 if List.is_empty tyl_sub
&& List.is_empty
tyl_super && exact_match
1490 (* This is side-effecting as it registers a dependency *)
1491 let class_def_sub = Env.get_class env cid_sub
in
1492 (* If class is final then exactness is superfluous *)
1494 match class_def_sub with
1495 | Some tc
-> Cls.final tc
1498 if not
(exact_match || is_final) then
1501 (* We handle the case where a generic A<T> is used as A *)
1504 List.is_empty
tyl_super
1505 && not
(Partial.should_check_error
(Env.get_mode env
) 4101)
1507 List.map tyl_sub
(fun _
->
1508 mk
(r_super, Typing_defs.make_tany
()))
1514 List.is_empty
tyl_sub
1515 && not
(Partial.should_check_error
(Env.get_mode env
) 4101)
1517 List.map
tyl_super (fun _
->
1518 mk
(r_super, Typing_defs.make_tany
()))
1522 if Int.( <> ) (List.length
tyl_sub) (List.length
tyl_super) then
1523 let n_sub = String_utils.soi
(List.length
tyl_sub) in
1524 let n_super = String_utils.soi
(List.length
tyl_super) in
1525 invalid_env_with env
(fun () ->
1526 Errors.type_arity_mismatch
1531 subtype_env.on_error
)
1533 let variance_reifiedl =
1534 if List.is_empty
tyl_sub then
1537 match class_def_sub with
1539 List.map
tyl_sub (fun _
->
1540 (Ast_defs.Invariant
, Aast.Erased
))
1542 List.map
(Cls.tparams class_sub
) (fun t
->
1543 (t
.tp_variance
, t
.tp_reified
))
1545 (* C<t1, .., tn> <: C<u1, .., un> iff
1546 * t1 <:v1> u1 /\ ... /\ tn <:vn> un
1547 * where vi is the variance of the i'th generic parameter of C,
1548 * and <:v denotes the appropriate direction of subtyping for variance v
1550 simplify_subtype_variance
1557 else if not
exact_match then
1560 let class_def_sub = Env.get_class env cid_sub
in
1561 (match class_def_sub with
1563 (* This should have been caught already in the naming phase *)
1566 (* We handle the case where a generic A<T> is used as A *)
1569 List.is_empty
tyl_sub
1570 && not
(Partial.should_check_error
(Env.get_mode env
) 4029)
1572 List.map
(Cls.tparams class_sub
) (fun _
->
1573 mk
(r_sub, Typing_defs.make_tany
()))
1579 type_expansions
= [];
1581 TUtils.make_locl_subst_for_class_tparams class_sub
tyl_sub;
1582 (* TODO: do we need this? *)
1583 this_ty = Option.value this_ty ~
default:ty_sub;
1586 on_error
= subtype_env.on_error
;
1589 let up_obj = Cls.get_ancestor class_sub cid_super
in
1592 let (env
, up_obj) = Phase.localize ~
ety_env env
up_obj in
1593 simplify_subtype ~
subtype_env ~
this_ty up_obj ty_super env
1596 Ast_defs.(equal_class_kind
(Cls.kind class_sub
) Ctrait
)
1597 || Ast_defs.(equal_class_kind
(Cls.kind class_sub
) Cinterface
)
1599 let rec try_upper_bounds_on_this up_objs env
=
1602 (* It's crucial that we don't lose updates to global_tpenv in env that were
1603 * introduced by PHase.localize. TODO: avoid this requirement *)
1605 | ub_obj_typ
:: up_objs
->
1606 (* a trait is never the runtime type, but it can be used
1607 * as a constraint if it has requirements or where constraints
1608 * for its using classes *)
1609 let (env
, ub_obj_typ
) =
1610 Phase.localize ~
ety_env env ub_obj_typ
1616 (mk
(r_sub, get_node ub_obj_typ
))
1618 ||| try_upper_bounds_on_this up_objs
1620 try_upper_bounds_on_this
1621 (Cls.upper_bounds_on_this class_sub
)
1625 | (r_sub, (Tvarray tv
| Tdarray
(_
, tv
) | Tvarray_or_darray
(_
, tv
))) ->
1626 (match (exact_super
, tyl_super) with
1627 | (Nonexact
, [tv_super
])
1628 when String.equal class_name
SN.Collections.cTraversable
1629 || String.equal class_name
SN.Rx.cTraversable
1630 || String.equal class_name
SN.Collections.cContainer
->
1631 (* vec<tv> <: Traversable<tv_super>
1632 * iff tv <: tv_super
1633 * Likewise for vec<tv> <: Container<tv_super>
1634 * and map<_,tv> <: Traversable<tv_super>
1635 * and map<_,tv> <: Container<tv_super>
1637 simplify_subtype ~
subtype_env ~
this_ty tv tv_super env
1638 | (Nonexact
, [tk_super
; tv_super
])
1639 when String.equal class_name
SN.Collections.cKeyedTraversable
1640 || String.equal class_name
SN.Rx.cKeyedTraversable
1641 || String.equal class_name
SN.Collections.cKeyedContainer
1642 || String.equal class_name
SN.Collections.cAnyArray
->
1643 (match get_node
ty_sub with
1649 (MakeType.int r_sub)
1651 &&& simplify_subtype ~
subtype_env ~
this_ty tv tv_super
1652 | Tvarray_or_darray
(tk
, _
)
1653 | Tdarray
(tk
, _
) ->
1655 |> simplify_subtype ~
subtype_env ~
this_ty tk tk_super
1656 &&& simplify_subtype ~
subtype_env ~
this_ty tv tv_super
1657 | _
-> default_subtype env
)
1659 when String.equal class_name
SN.Collections.cKeyedTraversable
1660 || String.equal class_name
SN.Rx.cKeyedTraversable
1661 || String.equal class_name
SN.Collections.cKeyedContainer
1662 || String.equal class_name
SN.Collections.cAnyArray
->
1663 (* All arrays are subtypes of the untyped KeyedContainer / Traversables *)
1665 | (_
, _
) -> default_subtype env
)
1666 | _
-> default_subtype env
)))
1668 and simplify_subtype_shape
1669 ~
(subtype_env : subtype_env)
1671 ~
(this_ty : locl_ty
option)
1672 (r_sub, shape_kind_sub
, fdm_sub
)
1673 (r_super, shape_kind_super
, fdm_super
) =
1675 Shape projection for shape type `s` and field `f` (`s |_ f`) is defined as:
1676 - if `f` appears in `s` as `f => ty` then `s |_ f` = `Required ty`
1677 - if `f` appears in `s` as `?f => ty` then `s |_ f` = `Optional ty`
1678 - if `f` does not appear in `s` and `s` is closed, then `s |_ f` = `Absent`
1679 - if `f` does not appear in `s` and `s` is open, then `s |_ f` = `Optional mixed`
1682 - `?f => nothing` should be ignored, and treated as `Absent`.
1683 Such a field cannot be given a value, and so is effectively not present.
1685 let shape_projection field_name shape_kind shape_map
r =
1686 match ShapeMap.find_opt field_name shape_map
with
1687 | Some
{ sft_ty
; sft_optional
} ->
1689 match (deref sft_ty
, sft_optional
) with
1690 | ((_
, Tunion
[]), true) -> `Absent
1691 | (_
, true) -> `Optional sft_ty
1692 | (_
, false) -> `Required sft_ty
1696 match shape_kind
with
1698 let printable_name =
1699 TUtils.get_printable_shape_field_name field_name
1703 (Reason.Rmissing_optional_field
(Reason.to_pos
r, printable_name))
1706 | Closed_shape
-> `Absent
1710 For two particular projections `p1` and `p2`, `p1` <: `p2` iff:
1711 - `p1` = `Required ty1`, `p2` = `Required ty2`, and `ty1` <: `ty2`
1712 - `p1` = `Required ty1`, `p2` = `Optional ty2`, and `ty1` <: `ty2`
1713 - `p1` = `Optional ty1`, `p2` = `Optional ty2`, and `ty1` <: `ty2`
1714 - `p1` = `Absent`, `p2` = `Optional ty2`
1715 - `p1` = `Absent`, `p2` = `Absent`
1716 We therefore need to handle all other cases appropriately.
1718 let simplify_subtype_shape_projection
1719 (r_sub, proj_sub
) (r_super, proj_super
) field_name res
=
1720 let printable_name = TUtils.get_printable_shape_field_name field_name
in
1721 match (proj_sub
, proj_super
) with
1722 (***** "Successful" cases - 5 / 9 total cases *****)
1723 | (`Required sub_ty
, `Required super_ty
)
1724 | (`Required sub_ty
, `Optional super_ty
)
1725 | (`Optional sub_ty
, `Optional super_ty
) ->
1726 res
&&& simplify_subtype ~
subtype_env ~
this_ty sub_ty super_ty
1727 | (`Absent
, `Optional _
)
1728 | (`Absent
, `Absent
) ->
1730 (***** Error cases - 4 / 9 total cases *****)
1731 | (`Required _
, `Absent
)
1732 | (`Optional _
, `Absent
) ->
1734 |> with_error
(fun () ->
1735 Errors.missing_field
1736 (Reason.to_pos
r_super)
1737 (Reason.to_pos
r_sub)
1739 subtype_env.on_error
)
1740 | (`Optional _
, `Required _
) ->
1742 |> with_error
(fun () ->
1743 Errors.required_field_is_optional
1744 (Reason.to_pos
r_sub)
1745 (Reason.to_pos
r_super)
1747 subtype_env.on_error
)
1748 | (`Absent
, `Required _
) ->
1750 |> with_error
(fun () ->
1751 Errors.missing_field
1752 (Reason.to_pos
r_sub)
1753 (Reason.to_pos
r_super)
1755 subtype_env.on_error
)
1757 (* Helper function to project out a field and then simplify subtype *)
1758 let shape_project_and_simplify_subtype
1759 (r_sub, shape_kind_sub
, shape_map_sub
)
1760 (r_super, shape_kind_super
, shape_map_super
)
1764 shape_projection field_name shape_kind_sub shape_map_sub
r_sub
1767 shape_projection field_name shape_kind_super shape_map_super
r_super
1769 simplify_subtype_shape_projection
1771 (r_super, proj_super)
1775 match (shape_kind_sub
, shape_kind_super
) with
1776 (* An open shape cannot subtype a closed shape *)
1777 | (Open_shape
, Closed_shape
) ->
1780 Errors.shape_fields_unknown
1781 (Reason.to_pos
r_sub)
1782 (Reason.to_pos
r_super)
1783 subtype_env.on_error
)
1785 (* Otherwise, all projections must subtype *)
1788 (shape_project_and_simplify_subtype
1789 (r_sub, shape_kind_sub
, fdm_sub
)
1790 (r_super, shape_kind_super
, fdm_super
))
1791 (ShapeSet.of_list
(ShapeMap.keys fdm_sub
@ ShapeMap.keys fdm_super
))
1794 and simplify_subtype_has_member
1798 ?
(nullsafe
: Reason.t
option)
1802 let using_new_method_call_inference =
1803 TypecheckerOptions.method_call_inference
(Env.get_tcopt env
)
1807 hm_type
= member_ty
;
1808 hm_class_id
= class_id
;
1809 hm_explicit_targs
= explicit_targs
;
1813 let is_method = Option.is_some explicit_targs
in
1814 (* If `nullsafe` is `Some _`, we are allowing the object type on LHS to be nullable. *)
1815 let mk_maybe_nullable env
ty =
1819 let null_ty = MakeType.null
r_null in
1820 Typing_union.union_i env
r_null ty null_ty
1822 let (env
, maybe_nullable_ty_super
) =
1823 let ty_super = mk_constraint_type
(r, Thas_member has_member_ty
) in
1824 mk_maybe_nullable env
(ConstraintType
ty_super)
1830 ~function_name
:"simplify_subtype_has_member"
1833 maybe_nullable_ty_super
;
1834 let (env
, ety_sub
) = Env.expand_internal_type env
ty_sub in
1835 let default_subtype env
=
1842 maybe_nullable_ty_super
1845 | ConstraintType cty
->
1846 (match deref_constraint_type cty
with
1852 hm_class_id
= cid_sub
;
1853 hm_explicit_targs
= explicit_targs_sub
;
1856 let targ_equal (_
, (_
, hint1
)) (_
, (_
, hint2
)) =
1857 Aast_defs.equal_hint_ hint1 hint2
1859 String.equal
(snd name_sub
) (snd name
)
1860 && class_id_equal cid_sub class_id
1862 (List.equal
targ_equal)
1866 simplify_subtype ~
subtype_env ~
this_ty ty_sub member_ty env
1869 | _
-> default_subtype env
)
1870 | LoclType
ty_sub ->
1871 (match deref
ty_sub with
1872 | (_
, (Tvar _
| Tunion _
| Terr
)) -> default_subtype env
1873 | (r_null, Tprim
Aast.Tnull
) when using_new_method_call_inference ->
1874 if Option.is_some nullsafe
then
1877 invalid env ~
fail:(fun () ->
1878 Errors.null_member_read
1882 (Reason.to_string
"This can be null" r_null))
1883 | (r_option
, Toption option_ty
) when using_new_method_call_inference ->
1884 if Option.is_some nullsafe
then
1885 simplify_subtype_has_member
1890 (LoclType option_ty
)
1894 let (env
, option_ty
) = Env.expand_type env option_ty
in
1895 (match get_node option_ty
with
1897 invalid env ~
fail:(fun () ->
1898 Errors.top_member_read
1903 (Typing_print.error env
ty_sub)
1904 (Reason.to_pos r_option
))
1906 invalid env ~
fail:(fun () ->
1907 Errors.null_member_read
1911 (Reason.to_string
"This can be null" r_option
)))
1912 | (_
, Tintersection tyl
)
1913 when let (_
, non_ty_opt
, _
) = find_type_with_exact_negation env tyl
in
1914 Option.is_some non_ty_opt
->
1915 (* use default_subtype to perform: A & B <: C <=> A <: C | !B *)
1917 | (r_inter
, Tintersection
[]) ->
1918 (* Tintersection [] = mixed *)
1919 invalid env ~
fail:(fun () ->
1920 Errors.top_member_read
1925 (Typing_print.error env
ty_sub)
1926 (Reason.to_pos r_inter
))
1927 | (r_inter
, Tintersection tyl
) when using_new_method_call_inference ->
1928 let (env
, tyl
) = List.map_env ~f
:Env.expand_type env tyl
in
1929 let subtype_fresh_has_member_ty env
ty_sub =
1930 let (env
, fresh_tyvar
) = Env.fresh_type env
(get_pos member_ty
) in
1931 let env = Env.set_tyvar_variance
env fresh_tyvar
in
1932 let fresh_has_member_ty =
1934 (r, Thas_member
{ has_member_ty
with hm_type
= fresh_tyvar
})
1936 let (env, maybe_nullable_fresh_has_member_ty
) =
1937 mk_maybe_nullable env (ConstraintType
fresh_has_member_ty)
1939 let (env, succeeded
) =
1945 maybe_nullable_fresh_has_member_ty
1949 match get_var fresh_tyvar
with
1951 Typing_solver.solve_to_equal_bound_or_wrt_variance
1955 subtype_env.on_error
1958 (env, Some fresh_tyvar
)
1962 let (env, fresh_tyvar_opts
) =
1963 TUtils.run_on_intersection
env tyl ~f
:subtype_fresh_has_member_ty
1965 let fresh_tyvars = List.filter_map ~f
:Fn.id fresh_tyvar_opts
in
1966 if List.is_empty
fresh_tyvars then
1967 (* TUtils.run_on_intersection has already added errors - no need to add more *)
1968 invalid ~
fail:(fun () -> ()) env
1970 let (env, intersection_ty
) =
1971 Inter.intersect_list
env r_inter
fresh_tyvars
1973 simplify_subtype ~
subtype_env ~
this_ty intersection_ty member_ty
env
1974 | (_
, Tnewtype
(_
, _
, newtype_ty
)) ->
1975 simplify_subtype_has_member
1980 (LoclType newtype_ty
)
1984 | (_, Tdependent _) ->
1985 | (_, Tgeneric _) ->
1988 let explicit_targs =
1989 match explicit_targs with
1991 | Some targs
-> targs
1993 let (errors
, (env, (obj_get_ty
, _tal
))) =
1994 Errors.do_
(fun () ->
1995 Typing_object_get.obj_get
1996 ~obj_pos
:(Reason.to_pos
r)
1998 ~coerce_from_ty
:None
2005 subtype_env.on_error
)
2008 if Errors.is_empty errors
then
2011 invalid
env ~
fail:(fun () -> Errors.merge_into_current errors
)
2013 prop &&& simplify_subtype ~
subtype_env ~
this_ty obj_get_ty member_ty
)
2015 and simplify_subtype_variance
2016 ~
(subtype_env : subtype_env)
2018 (variance_reifiedl : (Ast_defs.variance
* Aast.reify_kind
) list
)
2019 (children_tyl
: locl_ty list
)
2020 (super_tyl
: locl_ty list
) : env -> env * TL.subtype_prop
=
2022 let simplify_subtype reify_kind
=
2023 (* When doing coercions we treat dynamic as a bottom type. This is generally
2024 correct, except for the case when the generic isn't erased. When a generic is
2025 reified it is enforced as if it is it's own separate class in the runtime. i.e.
2028 class Box<reify T> {}
2029 function box_int(): Box<int> { return new Box<~int>(); }
2031 If is enforced like:
2032 class Box<reify T> {}
2033 class Box_int extends Box<int> {}
2034 class Box_like_int extends Box<~int> {}
2036 function box_int(): Box_int { return new Box_like_int(); }
2038 Thus we cannot push the like type to the outside of generic like we can
2043 if not
Aast.(equal_reify_kind reify_kind Erased
) then
2044 { subtype_env with treat_dynamic_as_bottom
= false }
2048 simplify_subtype ~
subtype_env ~
this_ty:None
2050 let simplify_subtype_variance = simplify_subtype_variance ~
subtype_env in
2051 match (variance_reifiedl, children_tyl
, super_tyl
) with
2056 | ( (variance
, reify_kind
) :: variance_reifiedl,
2058 super
:: superl
) ->
2059 let simplify_subtype = simplify_subtype reify_kind
in
2062 | Ast_defs.Covariant
-> simplify_subtype child super
env
2063 | Ast_defs.Contravariant
->
2066 ( Reason.Rcontravariant_generic
(get_reason
super, cid
),
2069 simplify_subtype super child
env
2070 | Ast_defs.Invariant
->
2072 mk
(Reason.Rinvariant_generic
(get_reason
super, cid
), get_node
super)
2074 env |> simplify_subtype child
super'
&&& simplify_subtype super' child
2076 &&& simplify_subtype_variance cid
variance_reifiedl childrenl superl
2078 and simplify_subtype_params
2079 ~
(subtype_env : subtype_env)
2080 ?
(is_method : bool = false)
2081 ?
(check_params_reactivity
= false)
2082 ?
(check_params_mutability
= false)
2083 ?
(check_params_ifc
= false)
2084 (subl
: locl_fun_param list
)
2085 (superl
: locl_fun_param list
)
2086 (variadic_sub_ty
: locl_possibly_enforced_ty
option)
2087 (variadic_super_ty
: locl_possibly_enforced_ty
option)
2089 let simplify_subtype_possibly_enforced =
2090 simplify_subtype_possibly_enforced ~
subtype_env
2092 let simplify_subtype_params = simplify_subtype_params ~
subtype_env in
2093 let simplify_subtype_params_with_variadic =
2094 simplify_subtype_params_with_variadic ~
subtype_env
2096 let simplify_supertype_params_with_variadic =
2097 simplify_supertype_params_with_variadic ~
subtype_env
2099 match (subl
, superl
) with
2100 (* When either list runs out, we still have to typecheck that
2101 the remaining portion sub/super types with the other's variadic.
2104 public function a(int $x = 0, string ... $args) // superl = [int], super_var = string
2108 public function a(string ... $args) // subl = [], sub_var = string
2110 , there should be an error because the first argument will be checked against
2111 int, not string that is, ChildClass::a("hello") would crash,
2112 but ParentClass::a("hello") wouldn't.
2114 Similarly, if the other list is longer, aka
2115 ChildClass extends ParentClass {
2116 public function a(mixed ... $args) // superl = [], super_var = mixed
2120 //subl = [string], sub_var = string
2121 public function a(string $x = 0, string ... $args)
2123 It should also check that string is a subtype of mixed.
2126 (match variadic_super_ty
with
2128 | Some
ty -> simplify_supertype_params_with_variadic superl
ty env)
2130 (match variadic_sub_ty
with
2132 | Some
ty -> simplify_subtype_params_with_variadic subl
ty env)
2133 | (sub
:: subl
, super :: superl
) ->
2136 if check_params_reactivity
then
2137 simplify_subtype_fun_params_reactivity ~
subtype_env sub
super
2142 if check_params_mutability
then
2147 (get_fp_mutability sub
)
2149 (get_fp_mutability
super)
2153 let { fp_type
= ty_sub; _
} = sub
in
2154 let { fp_type
= ty_super; _
} = super in
2155 (* Check that the calling conventions of the params are compatible. *)
2157 |> simplify_param_modes ~
subtype_env sub
super
2158 &&& simplify_param_accept_disposable ~
subtype_env sub
super
2160 if check_params_ifc
then
2161 simplify_param_ifc ~
subtype_env sub
super
2167 match (get_fp_mode sub
, get_fp_mode
super) with
2168 | (FPinout
, FPinout
) ->
2169 (* Inout parameters are invariant wrt subtyping for function types. *)
2171 |> simplify_subtype_possibly_enforced ty_super ty_sub
2172 &&& simplify_subtype_possibly_enforced ty_sub ty_super
2173 | _
-> env |> simplify_subtype_possibly_enforced ty_sub ty_super
2175 &&& simplify_subtype_params
2182 and simplify_subtype_params_with_variadic
2183 ~
(subtype_env : subtype_env)
2184 (subl
: locl_fun_param list
)
2185 (variadic_ty
: locl_possibly_enforced_ty
)
2187 let simplify_subtype_possibly_enforced =
2188 simplify_subtype_possibly_enforced ~
subtype_env
2190 let simplify_subtype_params_with_variadic =
2191 simplify_subtype_params_with_variadic ~
subtype_env
2195 | { fp_type
= sub
; _
} :: subl
->
2197 |> simplify_subtype_possibly_enforced sub variadic_ty
2198 &&& simplify_subtype_params_with_variadic subl variadic_ty
2200 and simplify_subtype_implicit_params
2201 ~
subtype_env { capability
= sub_cap
} { capability
= super_cap
} env =
2202 if TypecheckerOptions.any_coeffects
(Env.get_tcopt
env) then
2209 let expected = Typing_coeffects.get_type sub_cap
in
2210 let got = Typing_coeffects.get_type super_cap
in
2211 Errors.coeffect_subtyping_error
2213 (Typing_print.coeffects
env expected)
2215 (Typing_print.coeffects
env got)
2216 subtype_env.on_error
2220 match (sub_cap
, super_cap
) with
2221 | (CapTy sub
, CapTy
super) -> simplify_subtype ~
subtype_env sub
super env
2222 | (CapTy sub
, CapDefaults _p
) ->
2223 let super = Typing_coeffects.get_type super_cap
in
2224 simplify_subtype ~
subtype_env sub
super env
2225 | (CapDefaults _p
, CapTy
super) ->
2226 let sub = Typing_coeffects.get_type sub_cap
in
2227 simplify_subtype ~
subtype_env sub super env
2228 | (CapDefaults _p1
, CapDefaults _p2
) -> valid
env
2232 and simplify_supertype_params_with_variadic
2233 ~
(subtype_env : subtype_env)
2234 (superl
: locl_fun_param list
)
2235 (variadic_ty
: locl_possibly_enforced_ty
)
2237 let simplify_subtype_possibly_enforced =
2238 simplify_subtype_possibly_enforced ~
subtype_env
2240 let simplify_supertype_params_with_variadic =
2241 simplify_supertype_params_with_variadic ~
subtype_env
2245 | { fp_type
= super; _
} :: superl
->
2247 |> simplify_subtype_possibly_enforced variadic_ty
super
2248 &&& simplify_supertype_params_with_variadic superl variadic_ty
2250 and simplify_subtype_reactivity
2252 ?
(extra_info
: reactivity_extra_info
option)
2253 ?
(is_call_site
= false)
2255 (r_sub : reactivity
)
2257 (r_super : reactivity
)
2258 (env : env) : env * TL.subtype_prop
=
2261 "This function is " ^
TUtils.reactivity_to_string
env r_super ^
"."
2264 "This function is " ^
TUtils.reactivity_to_string
env r_sub ^
"."
2266 subtype_env.on_error
(p_super
, msg_super) [(p_sub
, msg_sub)]
2268 let ( ||| ) = ( ||| ) ~
fail in
2269 let invalid_env env = invalid ~
fail env in
2270 let maybe_localize t
=
2273 let ety_env = Phase.env_with_self
env in
2274 let (_
, t
) = Phase.localize ~
ety_env env t
in
2279 Option.bind extra_info
(fun { class_ty = cls
; _
} ->
2280 Option.map cls ~f
:maybe_localize)
2282 (* for method declarations check if condition type for r_super includes
2283 reactive method with a matching name. If yes - then it will act as a guarantee
2284 that derived class will have to redefine the method with a shape required
2285 by condition type (reactivity of redefined method must be subtype of reactivity
2286 of method in interface) *)
2287 let check_condition_type_has_matching_reactive_method env =
2288 (* function type TSub of method M with arbitrary reactivity in derive class
2289 can be subtype of conditionally reactive function type TSuper of method M
2290 defined in base class when condition type has reactive method M.
2293 public function f(): int;
2296 <<__RxIfImplements(Rx::class)>>
2297 public function f(): int { ... }
2300 public function f(): int { ... }
2302 This should be OK because:
2303 - B does not implement Rx (B::f is not compatible with Rx::f) which means
2304 that calling ($b : B)->f() will not be treated as reactive
2305 - if one of subclasses of B will decide to implement B - they will be forced
2306 to redeclare f which now will shadow B::f. Note that B::f will still be
2307 accessible as parent::f() but will be treated as non-reactive call.
2309 match (r_super, extra_info
) with
2310 | ( ( Pure
(Some condition_type_super
)
2311 | Reactive
(Some condition_type_super
)
2312 | Shallow
(Some condition_type_super
)
2313 | Local
(Some condition_type_super
) ),
2314 Some
{ method_info
= Some
(method_name
, is_static
); _
} ) ->
2316 ConditionTypes.try_get_method_from_condition_type
2318 condition_type_super
2323 (* check that reactivity of interface method (effectively a promised
2324 reactivity of a method in derived class) is a subtype of r_super.
2325 NOTE: we check only for unconditional reactivity since conditional
2326 version does not seems to yield a lot and will requre implementing
2327 cycle detection for condition types *)
2329 | Some
{ ce_type
= (lazy ty); _
} ->
2331 match get_node
ty with
2335 (Pure None
| Reactive None
| Shallow None
| Local None
) as
2341 empty_extra_info with
2342 parent_class_ty
= Some
(DeclTy condition_type_super
);
2345 simplify_subtype_reactivity
2353 | _
-> invalid_env env
2355 | _
-> invalid_env env
2357 | _
-> invalid_env env
2359 let is_some_cipp_or_pure r =
2364 | Nonreactive
-> false
2365 | _
-> not
(any_reactive
r)
2367 match (r_sub, r_super) with
2368 (* hardcode that cipp can't call noncipp and vice versa since we want to
2369 allow subtyping to aid in testing, but let normal calling checks handle
2370 cipp/pure v cipp/pure *)
2371 | (Cipp _
, _
) when is_call_site
&& not
(is_some_cipp_or_pure r_super) ->
2373 | (_
, Cipp _
) when is_call_site
&& not
(is_some_cipp_or_pure r_sub) ->
2375 (* anything is a subtype of nonreactive functions *)
2376 | (_
, Nonreactive
) -> valid
env
2377 (* to compare two maybe reactive values we need to unwrap them *)
2378 | (MaybeReactive
sub, MaybeReactive
super) ->
2379 simplify_subtype_reactivity
2388 (* for explicit checks at callsites implicitly unwrap maybereactive value:
2389 function f(<<__AtMostRxAsFunc>> F $f)
2390 f(<<__RxLocal>> () ==> {... })
2391 here parameter will be maybereactive and argument - rxlocal
2393 | (sub, MaybeReactive
super) when is_call_site
->
2394 simplify_subtype_reactivity
2403 (* if is_call_site is falst ignore maybereactive flavors.
2404 This usually happens during subtype checks for arguments and when target
2405 function is conditionally reactive we'll do the proper check
2406 in typing_reactivity.check_call. *)
2407 | (_
, MaybeReactive _
) when not is_call_site
-> valid
env
2409 class A { function f((function(): int) $f) {} }
2412 function f(<<__AtMostRxAsFunc>> (function(): int) $f);
2414 reactivity for arguments is checked contravariantly *)
2418 function f(<<__AtMostRxAsFunc>> (function(): int) $f) { return $f() } *)
2419 | (RxVar None
, RxVar _
) ->
2421 | (RxVar
(Some
sub), RxVar
(Some
super))
2422 | (sub, RxVar
(Some
super)) ->
2423 simplify_subtype_reactivity
2432 | (RxVar _
, _
) -> invalid_env env
2433 | ( (Local cond_sub
| Shallow cond_sub
| Reactive cond_sub
| Pure cond_sub
),
2435 | ((Shallow cond_sub
| Reactive cond_sub
| Pure cond_sub
), Shallow cond_super
)
2436 | ((Reactive cond_sub
| Pure cond_sub
), Reactive cond_super
)
2437 | (Pure cond_sub
, Pure cond_super
) ->
2439 |> simplify_subtype_param_rx_if_impl
2447 ||| check_condition_type_has_matching_reactive_method
2448 (* call_site specific cases *)
2449 (* shallow can call into local *)
2450 | (Local cond_sub
, Shallow cond_super
) when is_call_site
->
2451 simplify_subtype_param_rx_if_impl
2460 (* local can call into non-reactive, but not for inheritance *)
2461 | (Nonreactive
, Local _
) when is_call_site
-> valid
env
2462 (* Cipp(Local) can call pure *)
2463 | (Pure _
, (Cipp _
| CippLocal _
| CippRx
)) -> valid
env
2464 (* Cipp can call Cipp(Local) if the params match *)
2465 | (Cipp x
, Cipp y
) when Option.is_none x
|| Option.equal
String.equal x y
->
2467 | ((Cipp x
| CippLocal x
), CippLocal y
)
2468 when Option.is_none x
|| Option.equal
String.equal x y
->
2470 (* Unsafe direction is only legal for callsites *)
2471 | (CippLocal x
, Cipp y
)
2472 when (is_call_site
&& Option.is_none x
) || Option.equal
String.equal x y
->
2474 (* CippLocal can also call nonreactive *)
2475 | ( (Nonreactive
| Reactive _
| Local _
| Shallow _
| MaybeReactive _
),
2477 when is_call_site
->
2479 (* Anything can call CippGlobal*)
2480 (* CippRx is the same as CippGlobal, but with reactivity constraints *)
2481 (* Nonreactive is covered from above*)
2482 | ( (CippGlobal
| CippRx
),
2483 ( Reactive _
| Local _
| Shallow _
| MaybeReactive _
| Cipp _
2484 | CippLocal _
| CippGlobal
| CippRx
| Pure _
) ) ->
2486 (* CippGlobal can (safely) call anything the following *)
2487 | ((Pure _
| Cipp _
| CippLocal _
), CippGlobal
) -> valid
env
2488 (* CippGlobal can call anything (unsafe) *)
2489 | (_
, CippGlobal
) when is_call_site
-> valid
env
2490 | _
-> check_condition_type_has_matching_reactive_method env
2492 and should_check_fun_params_reactivity
(ft_super
: locl_fun_type
) =
2493 any_reactive ft_super
.ft_reactive
2495 (* checks condition described by OnlyRxIfImpl condition on parameter is met *)
2496 and simplify_subtype_param_rx_if_impl
2500 (cond_type_sub
: decl_ty
option)
2501 (declared_type_sub
: locl_ty
option)
2503 (cond_type_super
: decl_ty
option)
2504 (env : env) : env * TL.subtype_prop
=
2506 Option.map
cond_type_sub ~f
:(ConditionTypes.localize_condition_type env)
2508 let cond_type_super =
2509 Option.map
cond_type_super ~f
:(ConditionTypes.localize_condition_type env)
2511 let invalid_env env =
2513 TL.invalid ~
fail:(fun () ->
2514 Errors.rx_parameter_condition_mismatch
2515 SN.UserAttributes.uaOnlyRxIfImpl
2518 subtype_env.on_error
) )
2520 match (cond_type_sub, cond_type_super) with
2521 (* no condition types - do nothing *)
2522 | (None
, None
) -> valid
env
2523 (* condition type is specified only for super - ok for receiver case (is_param is false)
2525 <<__RxLocal, __OnlyRxIfImpl(Rx1::class)>>
2526 public abstract function condlocalrx(): int;
2528 abstract class B extends A {
2529 // ok to override cond local with local (if condition is not met - method
2530 // in base class is non-reactive )
2531 <<__Override, __RxLocal>>
2532 public function condlocalrx(): int {
2536 for parameters we need to verify that declared type of sub is a subtype of
2537 conditional type for super. Here is an example where this is violated:
2544 public function f(A $a): void {
2548 class C2 extends C1 {
2549 // ERROR: invariant f body is reactive iff $a instanceof RxA can be violated
2550 <<__Rx, __AtMostRxAsArgs>>
2551 public function f(<<__OnlyRxIfImpl(RxA::class)>>A $a): void {
2554 here declared type of sub is A
2555 and cond type of super is RxA
2557 | (None
, Some _
) when not is_param
-> valid
env
2558 | (None
, Some
cond_type_super) ->
2560 match declared_type_sub
with
2561 | None
-> invalid_env env
2562 | Some declared_type_sub
->
2563 simplify_subtype ~
subtype_env declared_type_sub
cond_type_super env
2565 (* condition types are set for both sub and super types: contravariant check
2567 interface B extends A {}
2568 interface C extends B {}
2571 <<__Rx, __OnlyRxIfImpl(B::class)>>
2572 public function f(): void;
2574 public function g(<<__OnlyRxIfImpl(B::class)>> A $a): void;
2576 interface I2 extends I1 {
2577 // OK since condition in I1::f covers I2::f
2578 <<__Rx, __OnlyRxIfImpl(A::class)>>
2579 public function f(): void;
2580 // OK since condition in I1::g covers I2::g
2582 public function g(<<__OnlyRxIfImpl(A::class)>> A $a): void;
2584 interface I3 extends I1 {
2585 // Error since condition in I1::f is less strict that in I3::f
2586 <<__Rx, __OnlyRxIfImpl(C::class)>>
2587 public function f(): void;
2588 // Error since condition in I1::g is less strict that in I3::g
2590 public function g(<<__OnlyRxIfImpl(C::class)>> A $a): void;
2593 | (Some
cond_type_sub, Some
cond_type_super) ->
2595 simplify_subtype ~
subtype_env cond_type_sub cond_type_super env
2597 simplify_subtype ~
subtype_env cond_type_super cond_type_sub env
2598 (* condition type is set for super type, check if declared type of
2599 subtype is a subtype of condition type
2602 public function f(int $a): void;
2605 <<__Rx, __OnlyRxIfImpl(Rx::class)>>
2606 public function f(T $a): void {
2609 // B <: Rx so B::f is completely reactive
2610 class B extends A<int> implements Rx {
2612 | (Some
cond_type_sub, None
) ->
2616 match declared_type_sub
with
2617 | None
-> invalid_env env
2618 | Some declared_type_sub
->
2619 simplify_subtype ~
subtype_env declared_type_sub
cond_type_sub env
2622 (* checks reactivity conditions for function parameters *)
2623 and simplify_subtype_fun_params_reactivity
2624 ~
subtype_env (p_sub
: locl_fun_param
) (p_super
: locl_fun_param
) env =
2625 match (p_sub
.fp_rx_annotation
, p_super
.fp_rx_annotation
) with
2626 (* no conditions on parameters - do nothing *)
2627 | (None
, None
) -> valid
env
2628 (* both parameters are conditioned to be rx function - no need to check anything *)
2629 | (Some Param_rx_var
, Some Param_rx_var
) -> valid
env
2630 | (None
, Some Param_rx_var
) ->
2631 (* parameter is conditionally reactive in supertype and missing condition
2632 in subtype - this is ok only if parameter in subtype is reactive
2634 function super((function(): int) $f);
2636 function sub(<<__AtMostRxAsFunc>> (function(): int) $f);
2637 We check if sub <: super. parameters are checked contravariantly
2638 so we need to verify that
2639 (function(): int) $f <: <<__AtMostRxAsFunc>> (function(): int) $f
2641 Suppose this is legal, then this will be allowed (in pseudo-code)
2643 function sub(<<__AtMostRxAsFunc>> (function(): int) $f) {
2644 $f(); // can call function here since it is conditionally reactive
2649 // invoke non-reactive code in reactive context which is bad
2650 $f(() ==> { echo 1; });
2653 It will be safe if parameter in super will be completely reactive,
2654 hence check below *)
2655 let (_
, p_sub_type
) = Env.expand_type
env p_sub
.fp_type
.et_type
in
2657 match get_node p_sub_type
with
2658 | Tfun tfun
when any_reactive tfun
.ft_reactive
-> valid
env
2661 TL.invalid ~
fail:(fun () ->
2662 Errors.rx_parameter_condition_mismatch
2663 SN.UserAttributes.uaAtMostRxAsFunc
2666 subtype_env.on_error
) )
2667 (* parameter type is not function - error will be reported in different place *)
2670 | (cond_sub
, cond_super
) ->
2673 | Some
(Param_rx_if_impl t
) -> Some t
2676 let cond_type_super =
2677 match cond_super
with
2678 | Some
(Param_rx_if_impl t
) -> Some t
2686 Errors.rx_parameter_condition_mismatch
2687 SN.UserAttributes.uaOnlyRxIfImpl
2690 subtype_env.on_error
);
2693 simplify_subtype_param_rx_if_impl
2698 (Some p_sub
.fp_type
.et_type
)
2703 and simplify_param_modes ~
subtype_env param1 param2
env =
2704 let { fp_pos
= pos1
; _
} = param1
in
2705 let { fp_pos
= pos2
; _
} = param2
in
2706 match (get_fp_mode param1
, get_fp_mode param2
) with
2707 | (FPnormal
, FPnormal
)
2708 | (FPinout
, FPinout
) ->
2710 | (FPnormal
, FPinout
) ->
2712 ~
fail:(fun () -> Errors.inoutness_mismatch pos2 pos1
subtype_env.on_error
)
2714 | (FPinout
, FPnormal
) ->
2716 ~
fail:(fun () -> Errors.inoutness_mismatch pos1 pos2
subtype_env.on_error
)
2719 and simplify_param_accept_disposable ~
subtype_env param1 param2
env =
2720 let { fp_pos
= pos1
; _
} = param1
in
2721 let { fp_pos
= pos2
; _
} = param2
in
2722 match (get_fp_accept_disposable param1
, get_fp_accept_disposable param2
) with
2726 Errors.accept_disposable_invariant pos1 pos2
subtype_env.on_error
)
2731 Errors.accept_disposable_invariant pos2 pos1
subtype_env.on_error
)
2733 | (_
, _
) -> valid
env
2735 and simplify_param_ifc ~
subtype_env sub super env =
2736 let { fp_pos
= pos1
; _
} = sub in
2737 let { fp_pos
= pos2
; _
} = super in
2738 (* TODO: also handle <<CanCall>> *)
2739 match (get_fp_ifc_external
sub, get_fp_ifc_external
super) with
2743 Errors.ifc_external_contravariant pos2 pos1
subtype_env.on_error
)
2747 and ifc_policy_matches
(ifc1
: ifc_fun_decl
) (ifc2
: ifc_fun_decl
) =
2748 match (ifc1
, ifc2
) with
2749 | (FDPolicied
(Some s1
), FDPolicied
(Some s2
)) when String.equal s1 s2
-> true
2750 | (FDPolicied None
, FDPolicied None
) -> true
2751 (* TODO(T79510128): IFC needs to check that the constraints inferred by the parent entail those by the subtype *)
2752 | (FDInferFlows
, FDInferFlows
) -> true
2755 (* Helper function for subtyping on function types: performs all checks that
2756 * don't involve actual types:
2757 * <<__ReturnDisposable>> attribute
2758 * <<__MutableReturn>> attribute
2759 * <<__Rx>> attribute
2760 * <<__Mutable>> attribute
2762 * <<__Policied>> attribute
2764 and simplify_subtype_funs_attributes
2766 ?
(extra_info : reactivity_extra_info
option)
2768 (ft_sub
: locl_fun_type
)
2769 (r_super : Reason.t
)
2770 (ft_super
: locl_fun_type
)
2772 let p_sub = Reason.to_pos
r_sub in
2773 let p_super = Reason.to_pos
r_super in
2774 let on_error_reactivity ?code
:_ _ _
=
2775 Errors.fun_reactivity_mismatch
2777 (TUtils.reactivity_to_string
env ft_super
.ft_reactive
)
2779 (TUtils.reactivity_to_string
env ft_sub
.ft_reactive
)
2780 subtype_env.on_error
2782 let ifc_policy_err_str = function
2783 | FDPolicied
(Some s
) -> s
2784 | FDPolicied None
-> "the existential policy"
2785 | FDInferFlows
-> "an inferred policy"
2787 simplify_subtype_reactivity
2788 ~
subtype_env:{ subtype_env with on_error
= on_error_reactivity }
2793 ft_super
.ft_reactive
2796 (ifc_policy_matches ft_sub
.ft_ifc_decl ft_super
.ft_ifc_decl
)
2798 Errors.ifc_policy_mismatch
2801 (ifc_policy_err_str ft_sub
.ft_ifc_decl
)
2802 (ifc_policy_err_str ft_super
.ft_ifc_decl
)
2803 subtype_env.on_error
)
2806 (get_ft_return_disposable ft_sub
)
2807 (get_ft_return_disposable ft_super
))
2809 Errors.return_disposable_mismatch
2810 (get_ft_return_disposable ft_super
)
2813 subtype_env.on_error
)
2814 |> (* it is ok for subclass to return mutably owned value and treat it as immutable -
2815 the fact that value is mutably owned guarantees it has only single reference so
2816 as a result this single reference will be immutable. However if super type
2817 returns mutable value and subtype yields immutable value - this is not safe.
2818 NOTE: error is not reported if child is non-reactive since it does not have
2819 immutability-by-default behavior *)
2822 (get_ft_returns_mutable ft_sub
)
2823 (get_ft_returns_mutable ft_super
)
2824 || (not
(get_ft_returns_mutable ft_super
))
2825 || not
(any_reactive ft_sub
.ft_reactive
) )
2827 Errors.mutable_return_result_mismatch
2828 (get_ft_returns_mutable ft_super
)
2831 subtype_env.on_error
)
2833 ( (not
(any_reactive ft_super
.ft_reactive
))
2834 || get_ft_returns_void_to_rx ft_super
2835 || not
(get_ft_returns_void_to_rx ft_sub
) )
2837 (* __ReturnsVoidToRx can be omitted on subtype, in this case using subtype
2838 via reference to supertype in rx context will be ok since result will be
2839 discarded. The opposite is not true:
2842 public function f(): A { return new A(); }
2845 <<__Rx, __Mutable, __ReturnsVoidToRx>>
2846 public function f(): A { return $this; }
2849 <<__Rx, __MutableReturn>>
2850 function f(): A { return new B(); }
2851 $a = HH\Rx\mutable(f());
2852 $a1 = $a->f(); // immutable alias to mutable reference *)
2853 Errors.return_void_to_rx_mismatch
2854 ~pos1_has_attribute
:true
2857 subtype_env.on_error
)
2859 (* check mutability only for reactive functions *)
2860 let check_params_mutability =
2861 any_reactive ft_super
.ft_reactive
&& any_reactive ft_sub
.ft_reactive
2864 ( if check_params_mutability (* check mutability of receivers *) then
2866 &&& check_mutability
2870 (get_ft_param_mutable ft_super
)
2872 (get_ft_param_mutable ft_sub
)
2876 (arity_min ft_sub
<= arity_min ft_super
)
2878 Errors.fun_too_many_args
2879 (arity_min ft_super
)
2883 subtype_env.on_error
)
2885 match (ft_sub
.ft_arity
, ft_super
.ft_arity
) with
2886 | (Fvariadic
{ fp_name
= None
; _
}, Fvariadic
{ fp_name
= Some _
; _
}) ->
2887 (* The HHVM runtime ignores "..." entirely, but knows about
2888 * "...$args"; for contexts for which the runtime enforces method
2889 * compatibility (currently, inheritance from abstract/interface
2890 * methods), letting "..." override "...$args" would result in method
2891 * compatibility errors at runtime. *)
2894 Errors.fun_variadicity_hh_vs_php56
p_sub p_super subtype_env.on_error
)
2896 | (Fstandard
, Fstandard
) ->
2897 let sub_max = List.length ft_sub
.ft_params
in
2898 let super_max = List.length ft_super
.ft_params
in
2899 if sub_max < super_max then
2902 Errors.fun_too_few_args
2907 subtype_env.on_error
)
2914 Errors.fun_unexpected_nonvariadic
p_sub p_super subtype_env.on_error
)
2918 and simplify_subtype_possibly_enforced
2919 ~
(subtype_env : subtype_env) et_sub et_super
=
2920 simplify_subtype ~
subtype_env et_sub
.et_type et_super
.et_type
2922 (* This implements basic subtyping on non-generic function types:
2923 * (1) return type behaves covariantly
2924 * (2) parameter types behave contravariantly
2925 * (3) special casing for variadics, and various reactivity and mutability attributes
2927 and simplify_subtype_funs
2928 ~
(subtype_env : subtype_env)
2929 ~
(check_return
: bool)
2930 ?
(extra_info : reactivity_extra_info
option)
2932 (ft_sub
: locl_fun_type
)
2933 (r_super : Reason.t
)
2934 (ft_super
: locl_fun_type
)
2935 env : env * TL.subtype_prop
=
2936 let variadic_subtype =
2937 match ft_sub
.ft_arity
with
2938 | Fvariadic
{ fp_type
= var_sub
; _
} -> Some var_sub
2941 let variadic_supertype =
2942 match ft_super
.ft_arity
with
2943 | Fvariadic
{ fp_type
= var_super
; _
} -> Some var_super
2946 let simplify_subtype_possibly_enforced =
2947 simplify_subtype_possibly_enforced ~
subtype_env
2949 let simplify_subtype_params = simplify_subtype_params ~
subtype_env in
2950 (* First apply checks on attributes and variadic arity *)
2951 let simplify_subtype_implicit_params =
2952 simplify_subtype_implicit_params ~
subtype_env
2955 |> simplify_subtype_funs_attributes
2962 &&& (* Now do contravariant subtyping on parameters *)
2964 match (variadic_subtype, variadic_supertype) with
2965 | (Some var_sub
, Some var_super
) ->
2966 simplify_subtype_possibly_enforced var_super var_sub
2970 let check_params_mutability =
2971 any_reactive ft_super
.ft_reactive
&& any_reactive ft_sub
.ft_reactive
2973 (* If both fun policies are IFC public, there's no need to check for inheritance issues *)
2974 (* There is the chance that the super function has an <<__External>> argument and the sub function does not,
2975 but <<__External>> on a public policied function literally just means the argument must be governed by the public policy,
2976 so should be an error in any case.
2978 let check_params_ifc =
2979 non_public_ifc ft_super
.ft_ifc_decl
2980 || non_public_ifc ft_sub
.ft_ifc_decl
2985 (Option.map
extra_info (fun i
-> Option.is_some i
.method_info
))
2988 simplify_subtype_params
2990 ~check_params_reactivity
:(should_check_fun_params_reactivity ft_super
)
2991 ~
check_params_mutability
2998 &&& simplify_subtype_implicit_params
2999 ft_super
.ft_implicit_params
3000 ft_sub
.ft_implicit_params
3002 (* Finally do covariant subtryping on return type *)
3003 if check_return
then
3004 simplify_subtype_possibly_enforced ft_sub
.ft_ret ft_super
.ft_ret
3008 (* One of the main entry points to this module *)
3010 ~
subtype_env (env : env) (ty_sub : internal_type
) (ty_super : internal_type
)
3012 Env.log_env_change
"sub_type" env
3014 let old_env = env in
3015 let (env, success
) =
3016 sub_type_inner ~
subtype_env env ~
this_ty:None
ty_sub ty_super
3025 ?
(allow_subtype_of_dynamic
= false)
3027 (ty_super : locl_ty
)
3032 ~allow_subtype_of_dynamic
3033 ~treat_dynamic_as_bottom
:false
3039 (* Add a new upper bound ty on var. Apply transitivity of sutyping,
3040 * so if we already have tyl <: var, then check that for each ty_sub
3041 * in tyl we have ty_sub <: ty.
3043 and add_tyvar_upper_bound_and_close
3044 ~treat_dynamic_as_bottom
(env, prop) var
ty on_error
=
3045 let upper_bounds_before = Env.get_tyvar_upper_bounds
env var
in
3047 Env.add_tyvar_upper_bound_and_update_variances
3048 ~intersect
:(try_intersect_i
env)
3053 let upper_bounds_after = Env.get_tyvar_upper_bounds
env var
in
3054 let added_upper_bounds = ITySet.diff
upper_bounds_after upper_bounds_before in
3055 let lower_bounds = Env.get_tyvar_lower_bounds
env var
in
3058 (fun upper_bound
(env, prop) ->
3060 Typing_subtype_tconst.make_all_type_consts_equal
3065 ~as_tyvar_with_cnstr
:true
3068 (fun lower_bound
(env, prop1
) ->
3072 (make_subtype_env ~treat_dynamic_as_bottom on_error
)
3077 (env, TL.conj prop1 prop2
))
3085 (* Add a new lower bound ty on var. Apply transitivity of subtyping
3086 * (so if var <: ty1,...,tyn then assert ty <: tyi for each tyi), using
3087 * simplify_subtype to produce a subtype proposition.
3089 and add_tyvar_lower_bound_and_close
3090 ~treat_dynamic_as_bottom
(env, prop) var
ty on_error
=
3091 let lower_bounds_before = Env.get_tyvar_lower_bounds
env var
in
3093 Env.add_tyvar_lower_bound_and_update_variances
3094 ~union
:(try_union_i
env)
3099 let lower_bounds_after = Env.get_tyvar_lower_bounds
env var
in
3100 let added_lower_bounds = ITySet.diff
lower_bounds_after lower_bounds_before in
3101 let upper_bounds = Env.get_tyvar_upper_bounds
env var
in
3104 (fun lower_bound
(env, prop) ->
3106 Typing_subtype_tconst.make_all_type_consts_equal
3111 ~as_tyvar_with_cnstr
:false
3114 (fun upper_bound
(env, prop1
) ->
3118 (make_subtype_env ~treat_dynamic_as_bottom on_error
)
3123 (env, TL.conj prop1 prop2
))
3131 and get_tyvar_opt t
=
3135 match get_node lt
with
3136 | Tvar var
-> Some var
3141 and props_to_env
env remain props on_error
=
3143 | [] -> (env, List.rev remain
)
3146 | TL.Conj props'
-> props_to_env
env remain
(props'
@ props
) on_error
3147 | TL.Disj
(f
, disj_props
) ->
3148 (* For now, just find the first prop in the disjunction that works *)
3149 let rec try_disj disj_props
=
3150 match disj_props
with
3152 (* For now let it fail later when calling
3153 process_simplify_subtype_result on the remaining constraints. *)
3154 props_to_env
env (TL.invalid ~
fail:f
:: remain
) props on_error
3155 | prop :: disj_props'
->
3156 let (env'
, other
) = props_to_env
env remain
[prop] on_error
in
3157 if TL.is_unsat
(TL.conj_list other
) then
3158 try_disj disj_props'
3160 props_to_env
env'
(remain
@ other
) props on_error
3163 | TL.IsSubtype
(ty_sub, ty_super) ->
3165 match (get_tyvar_opt
ty_sub, get_tyvar_opt
ty_super) with
3166 | (Some var_sub
, Some var_super
) ->
3168 add_tyvar_upper_bound_and_close
3169 ~treat_dynamic_as_bottom
:false
3176 add_tyvar_lower_bound_and_close
3177 ~treat_dynamic_as_bottom
:false
3183 props_to_env
env remain
(prop1
:: prop2
:: props
) on_error
3186 add_tyvar_upper_bound_and_close
3187 ~treat_dynamic_as_bottom
:false
3193 props_to_env
env remain
(prop :: props
) on_error
3196 add_tyvar_lower_bound_and_close
3197 ~treat_dynamic_as_bottom
:false
3203 props_to_env
env remain
(prop :: props
) on_error
3204 | _
-> props_to_env
env (prop :: remain
) props on_error
3206 | TL.Coerce
(ty_sub, ty_super) ->
3208 match (get_node
ty_sub, get_node
ty_super) with
3209 | (Tvar var_sub
, Tvar var_super
) ->
3211 add_tyvar_upper_bound_and_close
3212 ~treat_dynamic_as_bottom
:true
3219 add_tyvar_lower_bound_and_close
3220 ~treat_dynamic_as_bottom
:true
3226 props_to_env
env remain
(prop1
:: prop2
:: props
) on_error
3229 add_tyvar_upper_bound_and_close
3230 ~treat_dynamic_as_bottom
:true
3236 props_to_env
env remain
(prop :: props
) on_error
3239 add_tyvar_lower_bound_and_close
3240 ~treat_dynamic_as_bottom
:true
3246 props_to_env
env remain
(prop :: props
) on_error
3247 | _
-> failwith
"Coercion not expected"
3250 (* Move any top-level conjuncts of the form Tvar v <: t or t <: Tvar v to
3251 * the type variable environment. To do: use intersection and union to
3254 and prop_to_env
env prop on_error
=
3255 let (env, props'
) = props_to_env
env [] [prop] on_error
in
3256 (env, TL.conj_list props'
)
3260 ~
(subtype_env : subtype_env)
3261 ~
(this_ty : locl_ty
option)
3262 (ty_sub : internal_type
)
3263 (ty_super : internal_type
) : env * bool =
3267 ~function_name
:"sub_type_inner"
3272 simplify_subtype_i ~
subtype_env ~
this_ty ty_sub ty_super env
3274 let (env, prop) = prop_to_env
env prop subtype_env.on_error
in
3275 let env = Env.add_subtype_prop
env prop in
3276 let succeeded = process_simplify_subtype_result prop in
3279 and is_sub_type_alt_i
3280 ~ignore_generic_params
3282 ~treat_dynamic_as_bottom
3283 ~allow_subtype_of_dynamic
3287 let (this_ty, pos) =
3289 | LoclType ty1
-> (Some ty1
, get_pos ty1
)
3290 | ConstraintType _
-> (None
, Pos.none
)
3296 seen_generic_params
=
3297 ( if ignore_generic_params
then
3302 treat_dynamic_as_bottom
;
3303 allow_subtype_of_dynamic
;
3304 on_error
= Errors.unify_error_at
pos;
3307 (* It is weird that this can cause errors, but I am wary to discard them.
3308 * Using the generic unify_error to maintain current behavior. *)
3313 if TL.is_valid
prop then
3315 else if TL.is_unsat
prop then
3320 and is_sub_type_alt ~ignore_generic_params ~no_top_bottom
env ty1 ty2
=
3322 ~ignore_generic_params
3328 and is_sub_type
env ty1 ty2
=
3329 let ( = ) = Option.equal
Bool.equal
in
3331 ~ignore_generic_params
:false
3332 ~no_top_bottom
:false
3333 ~treat_dynamic_as_bottom
:false
3334 ~allow_subtype_of_dynamic
:false
3340 and is_sub_type_for_coercion
env ty1 ty2
=
3341 let ( = ) = Option.equal
Bool.equal
in
3343 ~ignore_generic_params
:false
3344 ~no_top_bottom
:false
3345 ~treat_dynamic_as_bottom
:true
3346 ~allow_subtype_of_dynamic
:true
3352 and is_sub_type_for_union
env ?allow_subtype_of_dynamic
:(asod
= false) ty1 ty2
=
3353 let ( = ) = Option.equal
Bool.equal
in
3355 ~ignore_generic_params
:false
3357 ~treat_dynamic_as_bottom
:false
3358 ~allow_subtype_of_dynamic
:asod
3364 and is_sub_type_for_union_i
env ?allow_subtype_of_dynamic
:(asod
= false) ty1 ty2
3366 let ( = ) = Option.equal
Bool.equal
in
3368 ~ignore_generic_params
:false
3370 ~treat_dynamic_as_bottom
:false
3371 ~allow_subtype_of_dynamic
:asod
3377 and can_sub_type
env ty1 ty2
=
3378 let ( <> ) a b
= not
(Option.equal
Bool.equal a b
) in
3380 ~ignore_generic_params
:false
3382 ~treat_dynamic_as_bottom
:false
3383 ~allow_subtype_of_dynamic
:false
3389 and is_sub_type_ignore_generic_params
env ty1 ty2
=
3390 let ( = ) = Option.equal
Bool.equal
in
3392 ~ignore_generic_params
:true
3394 ~treat_dynamic_as_bottom
:false
3395 ~allow_subtype_of_dynamic
:false
3401 and is_sub_type_ignore_generic_params_i
env ty1 ty2
=
3402 let ( = ) = Option.equal
Bool.equal
in
3404 ~ignore_generic_params
:true
3406 ~treat_dynamic_as_bottom
:false
3407 ~allow_subtype_of_dynamic
:false
3413 (* Attempt to compute the intersection of a type with an existing list intersection.
3414 * If try_intersect env t [t1;...;tn] = [u1; ...; um]
3415 * then u1&...&um must be the greatest lower bound of t and t1&...&tn wrt subtyping.
3417 * try_intersect nonnull [?C] = [C]
3418 * try_intersect t1 [t2] = [t1] if t1 <: t2
3419 * Note: it's acceptable to return [t;t1;...;tn] but the intention is that
3420 * we simplify (as above) wherever practical.
3421 * It can be assumed that the original list contains no redundancy.
3423 and try_intersect_i
env ty tyl
=
3427 if is_sub_type_ignore_generic_params_i
env ty ty'
then
3428 try_intersect_i
env ty tyl'
3429 else if is_sub_type_ignore_generic_params_i
env ty'
ty then
3432 let nonnull_ty = LoclType
(MakeType.nonnull
(reason
ty)) in
3433 let (env, ty) = Env.expand_internal_type
env ty in
3434 let (env, ty'
) = Env.expand_internal_type
env ty'
in
3435 let default env = ty'
:: try_intersect_i
env ty tyl'
in
3436 (match (ty, ty'
) with
3438 when is_sub_type_ignore_generic_params_i
env ty'
nonnull_ty ->
3440 match get_node lty
with
3441 | Toption t
-> try_intersect_i
env (LoclType t
) (ty'
:: tyl'
)
3445 when is_sub_type_ignore_generic_params_i
env ty nonnull_ty ->
3447 match get_node lty
with
3448 | Toption t
-> try_intersect_i
env (LoclType t
) (ty :: tyl'
)
3451 | (_
, _
) -> default env)
3453 and try_intersect
env ty tyl
=
3458 (List.map tyl ~f
:(fun ty -> LoclType
ty)))
3463 "The intersection of two locl type should always be a locl type.")
3465 (* Attempt to compute the union of a type with an existing list union.
3466 * If try_union env t [t1;...;tn] = [u1;...;um]
3467 * then u1|...|um must be the least upper bound of t and t1|...|tn wrt subtyping.
3469 * try_union int [float] = [num]
3470 * try_union t1 [t2] = [t1] if t2 <: t1
3473 * 1. It's acceptable to return [t;t1;...;tn] but the intention is that
3474 * we simplify (as above) wherever practical.
3475 * 2. Do not use Tunion for a syntactic union - the caller can do that.
3476 * 3. It can be assumed that the original list contains no redundancy.
3477 * TODO: there are many more unions to implement yet.
3479 and try_union_i
env ty tyl
=
3483 if is_sub_type_for_union_i
env ty ty'
then
3485 else if is_sub_type_for_union_i
env ty'
ty then
3486 try_union_i
env ty tyl'
3488 let (env, ty) = Env.expand_internal_type
env ty in
3489 let (env, ty'
) = Env.expand_internal_type
env ty'
in
3490 (match (ty, ty'
) with
3491 | (LoclType t1
, LoclType t2
)
3492 when (is_prim
Nast.Tfloat t1
&& is_prim
Nast.Tint t2
)
3493 || (is_prim
Nast.Tint t1
&& is_prim
Nast.Tfloat t2
) ->
3494 let num = LoclType
(MakeType.num (reason
ty)) in
3495 try_union_i
env num tyl'
3496 | (_
, _
) -> ty'
:: try_union_i
env ty tyl'
)
3498 and try_union
env ty tyl
=
3500 (try_union_i
env (LoclType
ty) (List.map tyl ~f
:(fun ty -> LoclType
ty)))
3503 | _
-> failwith
"The union of two locl type should always be a locl type.")
3505 let subtype_reactivity
3506 ?
extra_info ?is_call_site
env p_sub r_sub p_super r_super on_error
=
3507 let subtype_env = make_subtype_env ~treat_dynamic_as_bottom
:false on_error
in
3509 simplify_subtype_reactivity
3519 let (env, prop) = prop_to_env
env prop subtype_env.on_error
in
3520 ignore
(process_simplify_subtype_result prop);
3523 let decompose_subtype_add_bound
3524 (env : env) (ty_sub : locl_ty
) (ty_super : locl_ty
) : env =
3525 let (env, ty_super) = Env.expand_type
env ty_super in
3526 let (env, ty_sub) = Env.expand_type
env ty_sub in
3527 match (get_node
ty_sub, get_node
ty_super) with
3528 | (_
, Tany _
) -> env
3529 (* name_sub <: ty_super so add an upper bound on name_sub *)
3530 | (Tgeneric
(name_sub
, targs
), _
) when not
(phys_equal
ty_sub ty_super) ->
3531 (* TODO(T69551141) handle type arguments. Passing targs to get_lower_bounds,
3532 but the add_upper_bound call must be adapted *)
3536 ~function_name
:"decompose_subtype_add_bound"
3540 let tys = Env.get_upper_bounds
env name_sub targs
in
3541 (* Don't add the same type twice! *)
3542 if Typing_set.mem
ty_super tys then
3545 Env.add_upper_bound ~intersect
:(try_intersect
env) env name_sub
ty_super
3546 (* ty_sub <: name_super so add a lower bound on name_super *)
3547 | (_
, Tgeneric
(name_super
, targs
)) when not
(phys_equal
ty_sub ty_super) ->
3548 (* TODO(T69551141) handle type arguments. Passing targs to get_lower_bounds,
3549 but the add_lower_bound call must be adapted *)
3553 ~function_name
:"decompose_subtype_add_bound"
3557 let tys = Env.get_lower_bounds
env name_super targs
in
3558 (* Don't add the same type twice! *)
3559 if Typing_set.mem
ty_sub tys then
3562 Env.add_lower_bound ~union
:(try_union
env) env name_super
ty_sub
3565 (* Given two types that we know are in a subtype relationship
3566 * ty_sub <: ty_super
3567 * add to env.tpenv any bounds on generic type parameters that must
3568 * hold for ty_sub <: ty_super to be valid.
3570 * For example, suppose we know Cov<T> <: Cov<D> for a covariant class Cov.
3571 * Then it must be the case that T <: D so we add an upper bound D to the
3574 * Although some of this code is similar to that for sub_type_inner, its
3575 * purpose is different. sub_type_inner takes two types t and u and makes
3576 * updates to the substitution of type variables (through unification) to
3579 * decompose_subtype takes two types t and u for which t <: u is *assumed* to
3580 * hold, and makes updates to bounds on generic parameters that *necessarily*
3581 * hold in order for t <: u.
3583 let rec decompose_subtype
3587 (ty_super : locl_ty
)
3588 (on_error
: Errors.typing_error_callback
) : env =
3592 ~function_name
:"decompose_subtype"
3598 ~
subtype_env:(make_subtype_env ~seen_generic_params
:None on_error
)
3604 decompose_subtype_add_prop
p env prop
3606 and decompose_subtype_add_prop
p env prop =
3609 List.fold_left ~f
:(decompose_subtype_add_prop
p) ~init
:env props
3610 | TL.Disj
(_
, []) -> Env.mark_inconsistent
env
3611 | TL.Disj
(_
, [prop'
]) -> decompose_subtype_add_prop
p env prop'
3613 Typing_log.log_prop
2 env.function_pos
"decompose_subtype_add_prop" env prop;
3615 | TL.Coerce _
-> failwith
"Coercions should have been resolved beforehand"
3616 | TL.IsSubtype
(LoclType ty1
, LoclType ty2
) ->
3617 decompose_subtype_add_bound env ty1 ty2
3620 "Subtyping locl types should yield propositions involving locl types only."
3622 (* Decompose a general constraint *)
3623 and decompose_constraint
3626 (ck
: Ast_defs.constraint_kind
)
3628 (ty_super : locl_ty
) : env =
3629 (* constraints are caught based on reason, not error callback. Using unify_error *)
3631 | Ast_defs.Constraint_as
->
3632 decompose_subtype p env ty_sub ty_super (Errors.unify_error_at
p)
3633 | Ast_defs.Constraint_super
->
3634 decompose_subtype p env ty_super ty_sub (Errors.unify_error_at
p)
3635 | Ast_defs.Constraint_eq
->
3637 decompose_subtype p env ty_sub ty_super (Errors.unify_error_at
p)
3639 decompose_subtype p env ty_super ty_sub (Errors.unify_error_at
p)
3641 (* Given a constraint ty1 ck ty2 where ck is AS, SUPER or =,
3642 * add bounds to type parameters in the environment that necessarily
3643 * must hold in order for ty1 ck ty2.
3645 * First, we invoke decompose_constraint to add initial bounds to
3646 * the environment. Then we iterate, decomposing constraints that
3647 * arise through transitivity across bounds.
3649 * For example, suppose that env already contains
3651 * for some covariant class C. Now suppose we add the
3652 * constraint "T2 as C<T3>" i.e. we end up with
3653 * C<T1> <: T2 <: C<T3>
3654 * Then by transitivity we know that T1 <: T3 so we add this to the
3657 * We repeat this process until no further bounds are added to the
3658 * environment, or some limit is reached. (It's possible to construct
3659 * types that expand forever under inheritance.)
3661 let constraint_iteration_limit = 20
3666 (ck
: Ast_defs.constraint_kind
)
3668 (ty_super : locl_ty
) : env =
3672 ~function_name
:"add_constraint"
3676 let oldsize = Env.get_tpenv_size
env in
3677 let env = decompose_constraint
p env ck
ty_sub ty_super in
3678 let ( = ) = Int.equal
in
3679 if Env.get_tpenv_size
env = oldsize then
3682 let rec iter n
env =
3683 if n
> constraint_iteration_limit then
3686 let oldsize = Env.get_tpenv_size
env in
3689 (Env.get_generic_parameters
env)
3693 (* TODO(T70068435) always using [] as args for now *)
3694 (Typing_set.elements
(Env.get_lower_bounds
env x
[]))
3696 ~f
:(fun env ty_sub'
->
3698 (* TODO(T70068435) always using [] as args for now *)
3699 (Typing_set.elements
(Env.get_upper_bounds
env x
[]))
3701 ~f
:(fun env ty_super'
->
3707 (Errors.unify_error_at
p))))
3709 if Int.equal
(Env.get_tpenv_size
env) oldsize then
3716 let add_constraints p env constraints
=
3717 let add_constraint env (ty1
, ck
, ty2
) = add_constraint p env ck ty1 ty2
in
3718 List.fold_left constraints ~f
:add_constraint ~init
:env
3720 let sub_type_with_dynamic_as_bottom
3723 (ty_super : locl_ty
)
3724 (on_error
: Errors.typing_error_callback
) : env =
3725 let env_change_log = Env.log_env_change
"coercion" env in
3729 ~function_name
:"coercion"
3733 let old_env = env in
3736 ~
subtype_env:(make_subtype_env ~treat_dynamic_as_bottom
:true on_error
)
3742 let (env, prop) = prop_to_env
env prop on_error
in
3743 let env = Env.add_subtype_prop
env prop in
3744 let succeeded = process_simplify_subtype_result prop in
3753 let simplify_subtype_i env ty_sub ty_super ~on_error
=
3755 ~
subtype_env:(make_subtype_env ~no_top_bottom
:true on_error
)
3760 (*****************************************************************************)
3762 (*****************************************************************************)
3764 let sub_type_i env ty1 ty2 on_error
=
3766 ~
subtype_env:(make_subtype_env ~treat_dynamic_as_bottom
:false on_error
)
3772 ~
(check_return
: bool)
3773 ~
(extra_info : reactivity_extra_info
)
3776 (ft_sub
: locl_fun_type
)
3777 (r_super : Reason.t
)
3778 (ft_super
: locl_fun_type
)
3780 let old_env = env in
3782 simplify_subtype_funs
3783 ~
subtype_env:(make_subtype_env on_error
)
3792 let (env, prop) = prop_to_env
env prop on_error
in
3793 let env = Env.add_subtype_prop
env prop in
3794 let succeeded = process_simplify_subtype_result prop in
3800 let sub_type_or_fail env ty1 ty2
fail =
3801 sub_type
env ty1 ty2
(fun ?code
:_ _ _
-> fail ())
3803 let set_fun_refs () =
3804 Typing_utils.sub_type_ref
:= sub_type
;
3805 Typing_utils.sub_type_i_ref
:= sub_type_i;
3806 Typing_utils.sub_type_with_dynamic_as_bottom_ref
:=
3807 sub_type_with_dynamic_as_bottom;
3808 Typing_utils.add_constraint_ref
:= add_constraint;
3809 Typing_utils.is_sub_type_ref
:= is_sub_type
;
3810 Typing_utils.is_sub_type_for_union_ref
:= is_sub_type_for_union
;
3811 Typing_utils.is_sub_type_for_union_i_ref
:= is_sub_type_for_union_i
;
3812 Typing_utils.is_sub_type_ignore_generic_params_ref
:=
3813 is_sub_type_ignore_generic_params
3815 let () = set_fun_refs ()