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
28 (* We maintain a "visited" set for subtype goals. We do this only
29 * for goals of the form T <: t or t <: T where T is a generic parameter,
30 * as this is the more common case.
31 * T83096774: work out how to do this *efficiently* for all subtype goals.
33 * Here's a non-trivial example (assuming a contravariant type Contra).
34 * Under assumption T <: Contra<Contra<T>> show T <: Contra<T>.
35 * This leads to cycle of implications
37 * Contra<Contra<T>> <: Contra<T> =>
39 * at which point we are back at the original goal.
41 * Note that it's not enough to just keep a set of visited generic parameters,
42 * else we would reject good code e.g. consider
43 * class C extends B implements Contra<B>
44 * Now under assumption T <: C show T <: Contra<T>
45 * This leads to cycle of implications
48 * Contra<B> <: Contra<T> =>
49 * T <: B => // DO NOT REJECT here just because we've visited T before!
52 * We represent the visited set as a map from generic parameters
53 * to pairs of sets of types, such that an entry T := ({t1,...,tm},{u1,...,un})
54 * represents a set of goals
55 * T <: u1, ..., t <: un , t1 <: T, ..., tn <: T
57 module VisitedGoals
= struct
58 type t
= (ITySet.t
* ITySet.t
) SMap.t
60 let empty : t
= SMap.empty
62 (* Return None if (name <: ty) is already present, otherwise return Some v'
63 * where v' has the pair added
65 let try_add_visited_generic_sub v name ty
=
66 match SMap.find_opt name v
with
67 | None
-> Some
(SMap.add name
(ITySet.empty, ITySet.singleton ty
) v
)
68 | Some
(lower
, upper
) ->
69 if ITySet.mem ty upper
then
72 Some
(SMap.add name
(lower
, ITySet.add ty upper
) v
)
74 (* Return None if (ty <: name) is already present, otherwise return Some v'
75 * where v' has the pair added
77 let try_add_visited_generic_super v ty name
=
78 match SMap.find_opt name v
with
79 | None
-> Some
(SMap.add name
(ITySet.singleton ty
, ITySet.empty) v
)
80 | Some
(lower
, upper
) ->
81 if ITySet.mem ty lower
then
84 Some
(SMap.add name
(ITySet.add ty lower
, upper
) v
)
88 match get_node ty
with
93 require_soundness
: bool;
94 (** If set, requires the simplification of subtype constraints to be sound,
95 meaning that the simplified constraint must imply the original one. *)
96 require_completeness
: bool;
97 (** If set, requires the simplification of subtype constraints to be complete,
98 meaning that the original constraint must imply the simplified one.
99 If set, we also finish as soon as we see a goal of the form T <: t or
100 t <: T for generic parameter T *)
101 visited
: VisitedGoals.t
;
102 (** If above is not set, maintain a visited goal set *)
104 coerce
: TL.coercion_direction
option;
105 (** Coerce indicates whether subtyping should allow
106 coercion to or from dynamic. For coercion to dynamic, types that implement
107 dynamic are considered sub-types of dynamic. For coercion from dynamic,
108 dynamic is treated as a sub-type of all types. *)
109 on_error
: Typing_error.Reasons_callback.t
option;
110 tparam_constraints
: (Pos_or_decl.t
* Typing_defs.pos_id
) list
;
111 (** This is used for better error reporting to flag violated
112 constraints on type parameters, if any. *)
114 (** A flag which, if set, indicates that coeffects are being subtyped.
115 Note: this is a short-term solution to provide coeffects.pretty-printing of
116 `locl_ty`s that represent coeffects, since there is no good way to
117 tell apart coeffects from regular types *)
120 let coercing_from_dynamic se
=
122 | Some
TL.CoerceFromDynamic
-> true
125 let coercing_to_dynamic se
=
127 | Some
TL.CoerceToDynamic
-> true
131 ?
(require_soundness
= true)
132 ?
(require_completeness
= false)
133 ?
(no_top_bottom
= false)
135 ?
(is_coeffect
= false)
139 require_completeness
;
140 visited
= VisitedGoals.empty;
145 tparam_constraints
= [];
148 let possibly_add_violated_constraint subtype_env ~r_sub ~r_super
=
152 (match (r_super
, r_sub
) with
153 | (Reason.Rcstr_on_generics
(p
, tparam
), _
)
154 | (_
, Reason.Rcstr_on_generics
(p
, tparam
)) ->
155 (match subtype_env
.tparam_constraints
with
156 | (p_prev
, tparam_prev
) :: _
157 when Pos_or_decl.equal p p_prev
158 && Typing_defs.equal_pos_id tparam tparam_prev
->
159 (* since tparam_constraints is used for error reporting, it's
160 * unnecessary to add duplicates. *)
161 subtype_env
.tparam_constraints
162 | _
-> (p
, tparam
) :: subtype_env
.tparam_constraints
)
163 | _
-> subtype_env
.tparam_constraints
);
166 (* In typing_coercion.ml we sometimes check t1 <: t2 by adding dynamic
167 to check t1 < t|dynamic. In that case, we use the Rdynamic_coercion
168 reason so that we can detect it here and not print the dynamic if there
170 let detect_attempting_dynamic_coercion_reason r ty
=
172 | Reason.Rdynamic_coercion r
->
175 (match get_node lty
with
177 (match (get_node t1
, get_node t2
) with
178 | (Tdynamic
, _
) -> (r
, LoclType t2
)
179 | (_
, Tdynamic
) -> (r
, LoclType t1
)
185 (* Given a pair of types `ty_sub` and `ty_super` attempt to apply simplifications
186 * and add to the accumulated constraints in `constraints` any necessary and
187 * sufficient [(t1,ck1,u1);...;(tn,ckn,un)] such that
188 * ty_sub <: ty_super iff t1 ck1 u1, ..., tn ckn un
189 * where ck is `as` or `=`. Essentially we are making solution-preserving
190 * simplifications to the subtype assertion, for now, also generating equalities
191 * as well as subtype assertions, for backwards compatibility with use of
194 * If `constraints = []` is returned then the subtype assertion is valid.
196 * If the subtype assertion is unsatisfiable then return `failed = Some f`
197 * where `f` is a `unit-> unit` function that records an error message.
198 * (Sometimes we don't want to call this function e.g. when just checking if
201 * Elide singleton unions, treat invariant generics as both-ways
202 * subtypes, and actually chase hierarchy for extends and implements.
204 * Annoyingly, we need to pass env back too, because Typing_phase.localize
205 * expands type constants. (TODO: work out a better way of handling this)
208 * If assertion is valid (e.g. string <: arraykey) then
209 * result can be the empty list (i.e. nothing is added to the result)
210 * If assertion is unsatisfiable (e.g. arraykey <: string) then
211 * we record this in the failed field of the result.
214 let log_subtype_i ~level ~this_ty ~function_name env ty_sub ty_super
=
216 log_with_level env
"sub" ~level
(fun () ->
218 [Log_type_i
("ty_sub", ty_sub
); Log_type_i
("ty_super", ty_super
)]
221 Option.value_map this_ty ~default
:types ~f
:(fun ty
->
222 Log_type
("this_ty", ty
) :: types)
227 (Typing_utils.is_capability_i ty_sub
228 || Typing_utils.is_capability_i ty_super
)
231 (Reason.to_pos
(reason ty_sub
))
233 [Log_head
(function_name
, types)]
237 let log_subtype ~this_ty ~function_name env ty_sub ty_super
=
245 let is_final_and_invariant env id
=
246 let class_def = Env.get_class env id
in
248 | Some class_ty
-> TUtils.class_is_final_and_invariant class_ty
251 let is_tprim_disjoint tp1 tp2
=
252 let one_side tp1 tp2
=
254 match (tp1
, tp2
) with
258 | (Tarraykey
, Tstring
)
259 | (Tarraykey
, Tnum
) ->
262 ( Tnum
| Tint
| Tvoid
| Tbool
| Tarraykey
| Tfloat
| Tstring
| Tnull
263 | Tresource
| Tnoreturn
) ) ->
266 (not
(Aast_defs.equal_tprim tp1 tp2
)) && one_side tp1 tp2
&& one_side tp2 tp1
268 (* Two classes c1 and c2 are disjoint iff there exists no c3 such that
269 c3 <: c1 and c3 <: c2. *)
270 let is_class_disjoint env c1 c2
=
271 let is_interface_or_trait c_def
=
273 match Cls.kind c_def
with
282 if String.equal c1 c2
then
285 match (Env.get_class env c1
, Env.get_class env c2
) with
286 | (Some c1_def
, Some c2_def
) ->
287 if Cls.final c1_def
then
288 (* if c1 is final, then c3 would have to be equal to c1 *)
289 not
(Cls.has_ancestor c1_def c2
)
290 else if Cls.final c2_def
then
291 (* if c2 is final, then c3 would have to be equal to c2 *)
292 not
(Cls.has_ancestor c2_def c1
)
294 (* Given two non-final classes, if either is an interface or trait, then
295 there could be a c3, and so we consider the classes to not be disjoint.
296 However, if they are both classes, then c3 must be either c1 or c2 since
297 we don't have multiple inheritance. *)
298 (not
(is_interface_or_trait c1_def
))
299 && (not
(is_interface_or_trait c2_def
))
300 && (not
(Cls.has_ancestor c2_def c1
))
301 && not
(Cls.has_ancestor c1_def c2
)
303 (* This is a decl error that should have already been caught *)
306 (** [negate_ak_null_type env r ty] performs type negation similar to
307 TUtils.negate_type, but restricted to arraykey and null (and their
309 let negate_ak_null_type env r ty
=
310 let (env
, ty
) = Env.expand_type env ty
in
312 match get_node ty
with
313 | Tprim
Aast.Tnull
-> Some
(MakeType.nonnull r
)
314 | Tprim
Aast.Tarraykey
-> Some
(MakeType.neg r
(Neg_prim
Aast.Tarraykey
))
315 | Tneg
(Neg_prim
Aast.Tarraykey
) ->
316 Some
(MakeType.prim_type r
Aast.Tarraykey
)
317 | Tnonnull
-> Some
(MakeType.null r
)
322 let find_type_with_exact_negation env tyl
=
323 let rec find env tyl acc_tyl
=
325 | [] -> (env
, None
, acc_tyl
)
327 let (env
, neg_ty) = negate_ak_null_type env
(get_reason ty
) ty
in
329 | None
-> find env tyl'
(ty
:: acc_tyl
)
330 | Some
neg_ty -> (env
, Some
neg_ty, tyl'
@ acc_tyl
))
334 let describe_ty_default env ty
=
335 Typing_print.with_blank_tyvars
(fun () -> Typing_print.full_strip_ns_i env ty
)
337 let describe_ty ~is_coeffect
: env
-> internal_type
-> string =
338 (* Optimization: specialize on partial application, i.e.
339 * let describe_ty_sub = describe_ty ~is_coeffect in
340 * will check the flag only once, not every time the function is called *)
341 if not is_coeffect
then
345 | LoclType ty
-> Lazy.force
@@ Typing_coeffects.pretty env ty
346 | ty
-> describe_ty_default env ty
348 let rec describe_ty_super ~is_coeffect env ty
=
349 let describe_ty_super = describe_ty_super ~is_coeffect
in
350 let print = (describe_ty ~is_coeffect
) env
in
351 let default () = print ty
in
354 let (env
, ty
) = Env.expand_type env ty
in
355 (match get_node ty
with
357 let upper_bounds = ITySet.elements
(Env.get_tyvar_upper_bounds env v
) in
358 (* The constraint graph is transitively closed so we can filter tyvars. *)
360 List.filter
upper_bounds ~f
:(fun t
-> not
(is_tyvar_i t
))
362 (match upper_bounds with
363 | [] -> "some type not known yet"
365 let (locl_tyl
, cstr_tyl
) = List.partition_tf tyl ~f
:is_locl_type
in
367 match (locl_tyl
, cstr_tyl
) with
368 | (_
:: _
, _
:: _
) -> " and "
376 ^
(String.concat ~
sep:" & " (List.map tyl ~f
:print)
377 |> Markdown_lite.md_codify
)
382 (List.map cstr_tyl ~f
:(describe_ty_super env
))
384 "something " ^
locl_descr ^
sep ^
cstr_descr)
385 | Toption ty
when is_tyvar ty
->
386 "`null` or " ^
describe_ty_super env
(LoclType ty
)
387 | _
-> Markdown_lite.md_codify
(default ()))
388 | ConstraintType ty
->
389 (match deref_constraint_type ty
with
390 | (_
, Thas_member hm
) ->
395 hm_explicit_targs
= targs
;
400 | None
-> Printf.sprintf
"an object with property `%s`" name
401 | Some _
-> Printf.sprintf
"an object with method `%s`" name
)
402 | (_
, Thas_type_member
(id
, ty
)) ->
404 "an object with `type %s = %s`"
406 (describe_ty ~is_coeffect
:false env
(LoclType ty
))
407 | (_
, Tcan_traverse _
) -> "an array that can be traversed with foreach"
408 | (_
, Tcan_index _
) -> "an array that can be indexed"
409 | (_
, Tdestructure _
) ->
410 Markdown_lite.md_codify
411 (Typing_print.with_blank_tyvars
(fun () ->
412 Typing_print.full_strip_ns_i env
(ConstraintType ty
)))
413 | (_
, TCunion
(lty
, cty
)) ->
416 (describe_ty_super env
(LoclType lty
))
417 (describe_ty_super env
(ConstraintType cty
))
418 | (_
, TCintersection
(lty
, cty
)) ->
421 (describe_ty_super env
(LoclType lty
))
422 (describe_ty_super env
(ConstraintType cty
)))
424 let describe_ty_sub ~is_coeffect env ety
=
425 let ty_descr = describe_ty ~is_coeffect env ety
in
428 | Typing_defs.LoclType ty
-> Typing_print.constraints_for_type env ty
429 | Typing_defs.ConstraintType _
-> ""
432 let ( = ) = String.equal
in
434 (* Don't say `T as T` as it's not helpful (occurs in some coffect errors). *)
435 if ty_constraints = "as " ^
ty_descr then
437 else if ty_constraints = "" then
442 Markdown_lite.md_codify
(ty_descr ^
ty_constraints)
444 let simplify_subtype_by_physical_equality env ty_sub ty_super simplify_subtype
=
445 match (ty_sub
, ty_super
) with
446 | (LoclType ty1
, LoclType ty2
) when phys_equal ty1 ty2
-> (env
, TL.valid
)
447 | _
-> simplify_subtype
()
449 (* If it's clear from the syntax of the type that null isn't in ty, return true.
451 let rec null_not_subtype ty
=
452 match get_node ty
with
453 | Tprim
(Aast_defs.Tnull
| Aast_defs.Tvoid
)
465 | Tunion tys
-> List.for_all tys ~f
:null_not_subtype
474 | Tdependent
(_
, bound
)
475 | Tnewtype
(_
, _
, bound
) ->
476 null_not_subtype bound
478 let get_tyvar_opt t
=
482 match get_node lt
with
483 | Tvar var
-> Some var
488 (* build the interface corresponding to the can_traverse constraint *)
489 let can_traverse_to_iface ct
=
490 match (ct
.ct_key
, ct
.ct_is_await
) with
491 | (None
, false) -> MakeType.traversable ct
.ct_reason ct
.ct_val
492 | (None
, true) -> MakeType.async_iterator ct
.ct_reason ct
.ct_val
493 | (Some ct_key
, false) ->
494 MakeType.keyed_traversable ct
.ct_reason ct_key ct
.ct_val
495 | (Some ct_key
, true) ->
496 MakeType.async_keyed_iterator ct
.ct_reason ct_key ct
.ct_val
498 let liken ~super_like env ty
=
500 Typing_utils.make_like env ty
504 (* At present, we don't distinguish between coercions (<:D) and subtyping (<:) in the
505 * type variable and type parameter environments. When closing the environment we use subtyping (<:).
506 * To mitigate against this, when adding a dynamic upper bound wrt coercion,
507 * transform it first into supportdyn<mixed>,
508 * as t <:D dynamic iff t <: supportdyn<mixed>.
510 let transform_dynamic_upper_bound ~coerce env ty
=
511 if env
.in_support_dynamic_type_method_check
then
514 match (coerce
, get_node ty
) with
515 | (Some
TL.CoerceToDynamic
, Tdynamic
) ->
516 let r = get_reason ty
in
517 MakeType.supportdyn
r (MakeType.mixed
r)
518 | (Some
TL.CoerceToDynamic
, _
) -> ty
521 let mk_issubtype_prop ~coerce env ty1 ty2
=
525 (* If we are in dynamic-aware subtyping mode, that fact will be lost when ty2
526 ends up on the upper bound of a type variable. Here we find if ty2 contains
527 dynamic and replace it with supportdyn<mixed> which is equivalent, but does not
528 require dynamic-aware subtyping mode to be a supertype of types that support dynamic. *)
529 match (coerce
, Typing_utils.try_strip_dynamic env ty2
) with
530 | (Some
TL.CoerceToDynamic
, Some non_dyn_ty
) ->
531 let r = get_reason ty2
in
535 [non_dyn_ty
; MakeType.supportdyn
r (MakeType.mixed
r)] )
538 TL.IsSubtype
(coerce
, ty1
, LoclType ty2
)
539 | _
-> TL.IsSubtype
(coerce
, ty1
, ty2
)
541 let strip_supportdyn ty
=
542 match get_node ty
with
543 | Tnewtype
(name
, [tyarg
], _
) when String.equal name
SN.Classes.cSupportDyn
->
547 (** Given types ty_sub and ty_super, attempt to
548 * reduce the subtyping proposition ty_sub <: ty_super to
549 * a logical proposition whose primitive assertions are of the form v <: t or t <: v
550 * where v is a type variable.
552 * If super_like=true, then we have already reduced ty_sub <: ~ty_super to ty_sub <: ty_super
553 * with ty_super known to support dynamic (i.e. ty_super <: supportdyn<mixed>). In this case,
554 * when "going under" a constructor (for example, we had C<t> <: ~C<u>),
555 * we can apply "like pushing" on the components (in this example, t <: ~u).
556 * The parameter defaults to false to guard against incorrectly propagating the option. When
557 * simplifying ty_sub only (e.g. reducing t|u <: v to t<:v && u<:v) it is correct to
560 let rec simplify_subtype
561 ~
(subtype_env
: subtype_env
)
562 ?
(this_ty
: locl_ty
option = None
)
563 ?
(super_like
= false)
564 ?
(sub_supportdyn
= false)
565 ?
(super_supportdyn
= false)
577 and simplify_dynamic_aware_subtype ~subtype_env
=
579 ~subtype_env
:{ subtype_env
with coerce
= Some
TL.CoerceToDynamic
}
583 ~
(this_ty
: locl_ty
option)
584 ?
(super_like
= false)
590 (env
, mk_issubtype_prop ~coerce
:subtype_env
.coerce env ty_sub ty_super
)
592 let ( ||| ) = ( ||| ) ~fail
in
593 let (env
, ty_super
) = Env.expand_internal_type env ty_super
in
594 let (env
, ty_sub
) = Env.expand_internal_type env ty_sub
in
595 let default_subtype_inner env ty_sub ty_super
=
596 (* This inner function contains typing rules that are based solely on the subtype
597 * if you need to pattern match on the super type it should NOT be included
601 | ConstraintType cty_sub
->
603 match deref_constraint_type cty_sub
with
604 | (_
, TCunion
(lty_sub
, cty_sub
)) ->
606 |> simplify_subtype_i ~subtype_env
(LoclType lty_sub
) ty_super
607 &&& simplify_subtype_i ~subtype_env
(ConstraintType cty_sub
) ty_super
608 | (_
, TCintersection
(lty_sub
, cty_sub
)) ->
610 |> simplify_subtype_i ~subtype_env
(LoclType lty_sub
) ty_super
611 ||| simplify_subtype_i ~subtype_env
(ConstraintType cty_sub
) ty_super
612 | _
-> invalid ~fail env
614 | LoclType lty_sub
->
616 match deref lty_sub
with
621 * t1 <: t /\ ... /\ tn <: t
622 * We want this even if t is a type variable e.g. consider
625 List.fold_left tyl ~init
:(env
, TL.valid
) ~f
:(fun res ty_sub
->
627 &&& simplify_subtype_i
633 if subtype_env
.no_top_bottom
then
638 (* For subtyping queries of the form
640 * Tvar #id <: (Tvar #id | ...)
642 * `remove_tyvar_from_upper_bound` simplifies the union to
643 * `mixed`. This indicates that the query is discharged. If we find
644 * any other upper bound, we leave the subtyping query as it is.
646 let (env
, simplified_super_ty
) =
647 Typing_solver_utils.remove_tyvar_from_upper_bound env id ty_super
649 (* If the type is already in the upper bounds of the type variable,
650 * then we already know that this subtype assertion is valid
652 if ITySet.mem simplified_super_ty
(Env.get_tyvar_upper_bounds env id
)
656 let mixed = MakeType.mixed Reason.none
in
657 (match simplified_super_ty
with
658 | LoclType simplified_super_ty
659 when ty_equal simplified_super_ty
mixed ->
662 (* Special case if Tany is in an intersection on the left:
663 * t1 & ... & _ & ... & tn <: u
667 | (r, Tintersection tyl
) when List.exists tyl ~f
:is_any
->
671 (LoclType
(mk
(r, Typing_defs.make_tany
())))
674 | (r_sub
, Tintersection tyl
) ->
675 (* A & B <: C iif A <: C | !B *)
676 (match find_type_with_exact_negation env tyl
with
677 | (env
, Some non_ty
, tyl
) ->
678 let (env
, ty_super
) =
679 TUtils.union_i env
(get_reason non_ty
) ty_super non_ty
681 let ty_sub = MakeType.intersection r_sub tyl
in
682 simplify_subtype_i ~subtype_env
(LoclType
ty_sub) ty_super env
684 (* It's sound to reduce t1 & t2 <: t to (t1 <: t) || (t2 <: t), but
686 * TODO(T120921930): Don't do this if require_completeness is set.
690 ~init
:(env
, TL.invalid ~fail
)
691 ~f
:(fun res
ty_sub ->
692 let ty_sub = LoclType
ty_sub in
693 res
||| simplify_subtype_i ~subtype_env ~this_ty
ty_sub ty_super
))
694 | (_
, Tgeneric
(name_sub
, tyargs
)) ->
695 (* TODO(T69551141) handle type arguments. right now, just passing
696 * tyargs to Env.get_upper_bounds *)
697 (if subtype_env
.require_completeness
then
700 (* If we've seen this type parameter before then we must have gone
701 * round a cycle so we fail
704 VisitedGoals.try_add_visited_generic_sub
709 | None
-> invalid ~fail env
710 | Some new_visited
->
711 let subtype_env = { subtype_env with visited
= new_visited
} in
712 (* If the generic is actually an expression dependent type,
713 we need to update this_ty
717 DependentKind.is_generic_dep_ty name_sub
718 && Option.is_none
this_ty
724 (* Otherwise, we collect all the upper bounds ("as" constraints) on
725 the generic parameter, and check each of these in turn against
726 ty_super until one of them succeeds
728 let rec try_bounds tyl env
=
731 (* Try an implicit mixed = ?nonnull bound before giving up.
732 This can be useful when checking T <: t, where type t is
733 equivalent to but syntactically different from ?nonnull.
734 E.g., if t is a generic type parameter T with nonnull as
738 Reason.Rimplicit_upper_bound
(get_pos lty_sub
, "?nonnull")
740 let tmixed = LoclType
(MakeType.mixed r) in
742 |> simplify_subtype_i ~
subtype_env ~
this_ty tmixed ty_super
754 ||| simplify_subtype_i
764 (Env.get_upper_bounds env name_sub tyargs
)))
765 |> (* Turn error into a generic error about the type parameter *)
766 if_unsat
(invalid ~fail
)
767 | (_
, Tdynamic
) when coercing_from_dynamic subtype_env -> valid env
768 | (_
, Taccess _
) -> invalid ~fail env
769 | (_
, Tnewtype
(_
, _
, ty
)) ->
777 | (_
, Tdependent
(_
, ty
)) ->
778 let this_ty = Option.first_some
this_ty (Some lty_sub
) in
786 | _
-> invalid ~fail env
789 (* We further refine the default subtype case for rules that apply to all
790 * LoclTypes but not to ConstraintTypes
793 | LoclType lty_super
->
795 | ConstraintType _
-> default_subtype_inner env
ty_sub ty_super
796 | LoclType lty_sub
->
798 match deref lty_sub
with
801 match (subtype_env.coerce
, get_node lty_super
) with
802 | (Some
TL.CoerceToDynamic
, Tdynamic
) ->
803 let r = get_reason lty_super
in
804 let ty_super = MakeType.supportdyn
r (MakeType.mixed r) in
805 default_subtype_inner env
ty_sub (LoclType
ty_super)
812 (LoclType lty_super
) )
813 | (None
, _
) -> default_subtype_inner env
ty_sub ty_super
815 | (r_sub
, Tprim
Nast.Tvoid
) ->
817 Reason.Rimplicit_upper_bound
(Reason.to_pos r_sub
, "?nonnull")
825 |> if_unsat
(invalid ~fail
)
827 if subtype_env.no_top_bottom
then
831 | _
-> default_subtype_inner env
ty_sub ty_super
833 | ConstraintType _
-> default_subtype_inner env
ty_sub ty_super
835 (* Attempt to "solve" a subtype assertion ty_sub <: ty_super.
836 * Return a proposition that is logically stronger and simpler than
837 * the original assertion
838 * The logical relationship between the original and returned proposition
839 * depends on the flags require_soundness and require_completeness.
840 * Fail with Unsat error_function if
841 * the assertion is unsatisfiable. Some examples:
842 * string <: arraykey ==> True (represented as Conj [])
843 * (For covariant C and a type variable v)
844 * C<string> <: C<v> ==> string <: v
845 * (Assuming that C does *not* implement interface J)
847 * (Assuming we have T <: D in tpenv, and class D implements I)
848 * vec<T> <: vec<I> ==> True
849 * This last one would be left as T <: I if subtype_env.require_completeness=true
851 and simplify_subtype_i
852 ~
(subtype_env : subtype_env)
853 ?
(this_ty : locl_ty
option = None
)
854 ?
(super_like
: bool = false)
855 ?
(sub_supportdyn
: bool = false)
856 ?
(super_supportdyn
: bool = false)
857 (ty_sub : internal_type
)
858 (ty_super : internal_type
)
859 env
: env
* TL.subtype_prop
=
865 ^
(match subtype_env.coerce
with
867 | Some
TL.CoerceToDynamic
-> " <:D"
868 | Some
TL.CoerceFromDynamic
-> " D<:")
870 let flag str
= function
874 flag " super-like" super_like
875 ^
flag " require_soundness" subtype_env.require_soundness
876 ^
flag " require_completeness" subtype_env.require_completeness
)
880 simplify_subtype_by_physical_equality env
ty_sub ty_super @@ fun () ->
881 let (env
, ety_super
) = Env.expand_internal_type env
ty_super in
882 let (env
, ety_sub
) = Env.expand_internal_type env
ty_sub in
883 simplify_subtype_by_physical_equality env ety_sub ety_super
@@ fun () ->
885 possibly_add_violated_constraint
887 ~r_sub
:(reason ety_sub
)
888 ~r_super
:(reason ety_super
)
890 let fail_with_suffix snd_err_opt
=
893 (let r_super = reason ety_super
in
894 let r_sub = reason ety_sub
in
895 let (r_super, ety_super
) =
896 detect_attempting_dynamic_coercion_reason r_super ety_super
898 let is_coeffect = subtype_env.is_coeffect in
899 let ty_super_descr = describe_ty_super ~
is_coeffect env ety_super
in
900 let ty_sub_descr = describe_ty_sub ~
is_coeffect env ety_sub
in
901 let (ty_super_descr, ty_sub_descr) =
902 if String.equal
ty_super_descr ty_sub_descr then
903 ( "exactly the type " ^
ty_super_descr,
904 "the nonexact type " ^
ty_sub_descr )
906 (ty_super_descr, ty_sub_descr)
908 let left = Reason.to_string
("Expected " ^
ty_super_descr) r_super in
909 let right = Reason.to_string
("But got " ^
ty_sub_descr) r_sub in
913 let open Typing_error
in
914 match subtype_env.tparam_constraints
with
916 let snd_err1 = Secondary.Subtyping_error
reasons in
917 (match snd_err_opt
with
919 Option.map
subtype_env.on_error ~f
:(fun on_error
->
923 prepend_on_apply
(retain_code on_error
) snd_err1)
926 Option.map
subtype_env.on_error ~f
:(fun on_error
->
928 ~on_error
:(Reasons_callback.retain_code on_error
)
931 let snd_err1 = Secondary.Violated_constraint
{ cstrs
; reasons } in
932 (match snd_err_opt
with
934 Option.map
subtype_env.on_error ~f
:(fun on_error
->
936 ~on_error
:(Reasons_callback.prepend_on_apply on_error
snd_err1)
939 Option.map
subtype_env.on_error ~f
:(fun on_error
->
940 apply_reasons ~on_error
snd_err1))
945 let fail = fail_with_suffix None
in
946 let ( ||| ) = ( ||| ) ~
fail in
947 (* We *know* that the assertion is unsatisfiable *)
948 let invalid_env env
= invalid ~
fail env
in
949 let invalid_env_with env f
= invalid ~
fail:f env
in
950 (* We don't know whether the assertion is valid or not *)
952 (env
, mk_issubtype_prop ~coerce
:subtype_env.coerce env ety_sub ety_super
)
954 let default_subtype env
=
965 (* First deal with internal constraint types *)
966 | ConstraintType cty_super
->
967 let using_new_method_call_inference =
968 TypecheckerOptions.method_call_inference
(Env.get_tcopt env
)
971 match deref_constraint_type cty_super
with
972 | (_
, TCintersection
(lty
, cty
)) ->
974 | LoclType t
when is_union t
-> default_subtype env
975 | ConstraintType t
when is_constraint_type_union t
->
979 |> simplify_subtype_i ~
subtype_env ty_sub (LoclType lty
)
980 &&& simplify_subtype_i ~
subtype_env ty_sub (ConstraintType cty
))
981 | (_
, TCunion
(maybe_null
, maybe_has_member
))
982 when using_new_method_call_inference
983 && is_has_member maybe_has_member
985 let (_
, maybe_null
) = Env.expand_type env maybe_null
in
986 is_prim
Aast.Tnull maybe_null
->
987 (* `LHS <: Thas_member(...) | null` is morally a null-safe object access *)
988 let (env
, null_ty
) = Env.expand_type env maybe_null
in
989 let r_null = get_reason null_ty
in
990 let (r, has_member_ty
) = deref_constraint_type maybe_has_member
in
991 (match has_member_ty
with
992 | Thas_member has_member_ty
->
993 simplify_subtype_has_member
1001 | _
-> invalid_env env
(* Not possible due to guard in parent match *))
1002 | (_
, TCunion
(lty_super
, cty_super
)) ->
1004 | ConstraintType cty
when is_constraint_type_union cty
->
1006 | ConstraintType _
->
1008 |> simplify_subtype_i ~
subtype_env ty_sub (LoclType lty_super
)
1009 ||| simplify_subtype_i ~
subtype_env ty_sub (ConstraintType cty_super
)
1012 (match deref lty
with
1013 | (r, Toption ty
) ->
1014 let ty_null = MakeType.null
r in
1023 &&& simplify_subtype_i ~
subtype_env ~
this_ty (LoclType ty
) ty_super
1024 | (_
, (Tintersection _
| Tunion _
| Terr
| Tvar _
)) ->
1028 |> simplify_subtype_i ~
subtype_env ty_sub (LoclType lty_super
)
1029 ||| simplify_subtype_i
1032 (ConstraintType cty_super
)
1033 ||| default_subtype))
1034 | (r_super, Tdestructure
{ d_required
; d_optional
; d_variadic
; d_kind
})
1036 (* List destructuring *)
1037 let destructure_array t env
=
1038 (* If this is a splat, there must be a variadic box to receive the elements
1039 * but for list(...) destructuring this is not required. Example:
1041 * function f(int $i): void {}
1042 * function g(vec<int> $v): void {
1043 * list($a) = $v; // ok (but may throw)
1044 * f(...$v); // error
1048 | Reason.Runpack_param
(_
, fpos, _
) -> fpos
1049 | _
-> Reason.to_pos
r_super
1051 match (d_kind
, d_required
, d_variadic
) with
1052 | (SplatUnpack
, _
:: _
, _
) ->
1053 (* return the env so as not to discard the type variable that might
1054 have been created for the Traversable type created below. *)
1057 (Option.map
subtype_env.on_error ~f
:(fun on_error
->
1059 apply_reasons ~on_error
1060 @@ Secondary.Unpack_array_required_argument
1061 { pos
= Reason.to_pos
r_super; decl_pos
= fpos })))
1062 | (SplatUnpack
, [], None
) ->
1065 (Option.map
subtype_env.on_error ~f
:(fun on_error
->
1067 apply_reasons ~on_error
1068 @@ Secondary.Unpack_array_variadic_argument
1069 { pos
= Reason.to_pos
r_super; decl_pos
= fpos })))
1070 | (SplatUnpack
, [], Some _
)
1071 | (ListDestructure
, _
, _
) ->
1072 List.fold d_required ~init
:(env
, TL.valid
) ~f
:(fun res ty_dest
->
1073 res
&&& simplify_subtype ~
subtype_env ~
this_ty t ty_dest
)
1075 List.fold d_optional ~init
:(env
, TL.valid
) ~f
:(fun res ty_dest
->
1076 res
&&& simplify_subtype ~
subtype_env ~
this_ty t ty_dest
)
1078 Option.value_map ~
default:(env
, TL.valid
) d_variadic ~f
:(fun vty
->
1079 simplify_subtype ~
subtype_env ~
this_ty t vty env
)
1082 let destructure_tuple r ts env
=
1083 (* First fill the required elements. If there are insufficient elements, an error is reported.
1084 * Fill as many of the optional elements as possible, and the remainder are unioned into the
1085 * variadic element. Example:
1087 * (float, bool, string, int) <: Tdestructure(#1, opt#2, ...#3) =>
1088 * float <: #1 /\ bool <: #2 /\ string <: #3 /\ int <: #3
1090 * (float, bool) <: Tdestructure(#1, #2, opt#3) =>
1091 * float <: #1 /\ bool <: #2
1093 let len_ts = List.length ts
in
1094 let len_required = List.length d_required
in
1096 let (epos
, fpos, prefix
) =
1098 | Reason.Runpack_param
(epos
, fpos, c
) ->
1099 (Pos_or_decl.of_raw_pos epos
, fpos, c
)
1100 | _
-> (Reason.to_pos
r_super, Reason.to_pos
r, 0)
1105 (prefix
+ len_required)
1109 subtype_env.on_error
)
1111 if len_ts < len_required then
1112 arity_error (fun expected actual pos decl_pos on_error_opt
->
1113 Option.map on_error_opt ~f
:(fun on_error
->
1115 Typing_error.Secondary.Typing_too_few_args
1116 { pos
; decl_pos
; expected
; actual
}
1118 Typing_error.(apply_reasons ~on_error
base_err)))
1120 let len_optional = List.length d_optional
in
1121 let (ts_required
, remain
) = List.split_n ts
len_required in
1122 let (ts_optional
, ts_variadic
) = List.split_n remain
len_optional in
1126 ~init
:(env
, TL.valid
)
1127 ~f
:(fun res ty ty_dest
->
1128 res
&&& simplify_subtype ~
subtype_env ~
this_ty ty ty_dest
)
1130 let len_ts_opt = List.length ts_optional
in
1131 let d_optional_part =
1132 if len_ts_opt < len_optional then
1133 List.take d_optional
len_ts_opt
1140 ~init
:(env
, TL.valid
)
1141 ~f
:(fun res ty ty_dest
->
1142 res
&&& simplify_subtype ~
subtype_env ~
this_ty ty ty_dest
)
1144 match (ts_variadic
, d_variadic
) with
1145 | (vars
, Some vty
) ->
1146 List.fold vars ~init
:(env
, TL.valid
) ~f
:(fun res ty
->
1147 res
&&& simplify_subtype ~
subtype_env ~
this_ty ty vty
)
1148 | ([], None
) -> valid env
1150 (* Elements remain but we have nowhere to put them *)
1151 arity_error (fun expected actual pos decl_pos on_error_opt
->
1152 Option.map on_error_opt ~f
:(fun on_error
->
1154 apply_reasons ~on_error
1155 @@ Secondary.Typing_too_many_args
1156 { pos
; decl_pos
; expected
; actual
})))
1159 let destructure_dynamic t env
=
1160 if TypecheckerOptions.enable_sound_dynamic
(Env.get_tcopt env
) then
1161 List.fold d_required ~init
:(env
, TL.valid
) ~f
:(fun res ty_dest
->
1162 res
&&& simplify_subtype ~
subtype_env ~
this_ty t ty_dest
)
1164 List.fold d_optional ~init
:(env
, TL.valid
) ~f
:(fun res ty_dest
->
1165 res
&&& simplify_subtype ~
subtype_env ~
this_ty t ty_dest
)
1167 Option.value_map ~
default:(env
, TL.valid
) d_variadic ~f
:(fun vty
->
1168 simplify_subtype ~
subtype_env ~
this_ty t vty env
)
1170 env
|> destructure_array t
1174 | ConstraintType _
-> default_subtype env
1175 | LoclType
ty_sub ->
1176 (match deref
ty_sub with
1177 | (r, Ttuple tyl
) -> env
|> destructure_tuple r tyl
1178 | (r, Tclass
((_
, x
), _
, tyl
))
1179 when String.equal x
SN.Collections.cPair
->
1180 env
|> destructure_tuple r tyl
1181 | (_
, Tclass
((_
, x
), _
, [elt_type
]))
1182 when String.equal x
SN.Collections.cVector
1183 || String.equal x
SN.Collections.cImmVector
1184 || String.equal x
SN.Collections.cVec
1185 || String.equal x
SN.Collections.cConstVector
->
1186 env
|> destructure_array elt_type
1187 | (_
, Tdynamic
) -> env
|> destructure_dynamic ty_sub
1188 (* TODO: should remove these any cases *)
1190 let any = mk
(r, Typing_defs.make_tany
()) in
1191 env
|> destructure_array any
1192 | (_
, (Tunion _
| Tintersection _
| Tgeneric _
| Tvar _
)) ->
1193 (* TODO(T69551141) handle type arguments of Tgeneric? *)
1199 (* Allow splatting of arbitrary Traversables *)
1200 let (env
, ty_inner
) = Env.fresh_type env
Pos.none
in
1201 let traversable = MakeType.traversable r_super ty_inner
in
1203 |> simplify_subtype ~
subtype_env ~
this_ty ty_sub traversable
1204 &&& destructure_array ty_inner
1205 | ListDestructure
->
1208 (Typing_print.with_blank_tyvars
(fun () ->
1209 Typing_print.full_strip_ns env
ty_sub))
1212 |> if_unsat
@@ fun env
->
1216 subtype_env.on_error
1220 apply_reasons ~on_error
1221 @@ Secondary.Invalid_destructure
1223 pos
= Reason.to_pos
r_super;
1224 decl_pos
= get_pos
ty_sub;
1225 ty_name
= ty_sub_descr;
1229 | (r, Tcan_index ci
) ->
1230 simplify_subtype_can_index
1238 | (r, Tcan_traverse ct
) ->
1239 simplify_subtype_can_traverse
1247 | (r, Thas_member has_member_ty
) ->
1248 simplify_subtype_has_member
1255 | (r, Thas_type_member
(id
, ty
)) ->
1256 simplify_subtype_has_type_member
1264 (* Next deal with all locl types *)
1265 | LoclType
ty_super ->
1266 (match deref
ty_super with
1269 | ConstraintType cty
when is_constraint_type_union cty
->
1271 | ConstraintType _
->
1272 if subtype_env.no_top_bottom
then
1277 (match deref lty
with
1278 | (_
, Tunion _
) -> default_subtype env
1279 | (_
, Terr
) -> valid env
1281 if subtype_env.no_top_bottom
then
1285 | (_
, Tvar var_super
) ->
1287 | ConstraintType cty
when is_constraint_type_union cty
->
1289 | ConstraintType _
-> default env
1290 | LoclType
ty_sub ->
1291 (match deref
ty_sub with
1292 | (_
, (Tunion _
| Terr
)) -> default_subtype env
1293 | (_
, Tdynamic
) when coercing_from_dynamic subtype_env ->
1295 (* We want to treat nullable as a union with the same rule as above.
1296 * This is only needed for Tvar on right; other cases are dealt with specially as
1300 let (env
, t
) = Env.expand_type env t
in
1301 (match get_node t
with
1302 (* We special case on `mixed <: Tvar _`, adding the entire `mixed` type
1303 as a lower bound. This enables clearer error messages when upper bounds
1304 are added to the type variable: transitive closure picks up the
1305 entire `mixed` type, and not separately consider `null` and `nonnull` *)
1306 | Tnonnull
-> default env
1308 let ty_null = MakeType.null
r in
1310 |> simplify_subtype ~
subtype_env ~
this_ty ~super_like t
ty_super
1311 &&& simplify_subtype ~
subtype_env ~
this_ty ty_null ty_super)
1312 | (_
, Tvar var_sub
) when Ident.equal var_sub var_super
-> valid env
1315 match subtype_env.coerce
with
1322 (LoclType
ty_super) )
1323 | None
-> default env
1325 | (_
, Tintersection tyl
) ->
1327 | ConstraintType cty
when is_constraint_type_union cty
->
1329 | LoclType lty
when is_union lty
-> default_subtype env
1330 | LoclType lty
when is_err lty
-> valid env
1331 (* t <: (t1 & ... & tn)
1333 * t <: t1 /\ ... /\ t <: tn
1336 List.fold_left tyl ~init
:(env
, TL.valid
) ~f
:(fun res
ty_super ->
1337 let ty_super = LoclType
ty_super in
1338 res
&&& simplify_subtype_i ~
subtype_env ~
this_ty ty_sub ty_super))
1339 (* Empty union encodes the bottom type nothing *)
1340 | (_
, Tunion
[]) -> default_subtype env
1341 (* ty_sub <: union{ty_super'} iff ty_sub <: ty_super' *)
1342 | (_
, Tunion
[ty_super'
]) ->
1348 (LoclType
ty_super'
)
1350 | (r, Tunion
(_
:: _
as tyl_super
)) ->
1351 let simplify_sub_union env
ty_sub tyl_super
=
1356 match get_node lty
with
1361 | _
-> invalid_env env
1363 | _
-> invalid_env env
1365 let stripped_dynamic =
1366 if TypecheckerOptions.enable_sound_dynamic env
.genv
.tcopt
then
1367 TUtils.try_strip_dynamic_from_union env
r tyl_super
1371 match stripped_dynamic with
1373 when is_sub_type_for_union_i
1376 (LoclType
(MakeType.supportdyn
r (MakeType.mixed r))) ->
1378 |> simplify_subtype_i
1382 (LoclType
(MakeType.dynamic
r))
1383 ||| simplify_subtype_i
1391 (* Implement the declarative subtyping rule C<~t1,...,~tn> <: ~C<t1,...,tn>
1392 * for a type C<t1,...,tn> that supports dynamic. Algorithmically,
1393 * t <: ~C<t1,...,tn> iff
1394 * t <: C<~t1,...,~tn> /\ C<~t1,...,~tn> <:D dynamic.
1395 * An SDT class C generalizes to other SDT constructors such as tuples and shapes.
1398 match stripped_dynamic with
1399 | None
-> finish env
1401 let (env
, opt_ty
) = Typing_dynamic.try_push_like env ty
in
1403 | None
-> finish env
1405 let simplify_pushed_like env
=
1407 |> simplify_dynamic_aware_subtype
1411 (MakeType.dynamic
Reason.Rnone
)
1412 &&& simplify_subtype_i
1418 env
|> simplify_pushed_like ||| finish)
1421 (* It's sound to reduce t <: t1 | t2 to (t <: t1) || (t <: t2). But
1422 * not complete e.g. consider (t1 | t3) <: (t1 | t2) | (t2 | t3).
1423 * But we deal with unions on the left first (see case above), so this
1424 * particular situation won't arise.
1425 * TODO: identify under what circumstances this reduction is complete.
1426 * TODO(T120921930): Don't do this if require_completeness is set.
1428 let rec try_disjuncts tys env
=
1430 | [] -> try_push env
1432 let ty = LoclType
ty in
1434 |> simplify_subtype_i ~
subtype_env ~
this_ty ~super_like
ty_sub ty
1435 ||| try_disjuncts tys
1437 env
|> try_disjuncts tyl_super
1441 | ConstraintType cty
when is_constraint_type_union cty
->
1443 | ConstraintType _
-> simplify_sub_union env ety_sub tyl_super
1444 | LoclType lty_sub
->
1446 simplify_subtype_arraykey_union
1453 | (env
, Some props
) -> (env
, props
)
1455 (match deref lty_sub
with
1456 | (_
, (Tunion _
| Terr
| Tvar _
)) -> default_subtype env
1457 | (_
, Tgeneric _
) when subtype_env.require_completeness
->
1459 (* Num is not atomic: it is equivalent to int|float. The rule below relies
1460 * on ty_sub not being a union e.g. consider num <: arraykey | float, so
1461 * we break out num first.
1463 | (r, Tprim
Nast.Tnum
) ->
1464 let ty_float = MakeType.float r and ty_int
= MakeType.int r in
1466 |> simplify_subtype ~
subtype_env ~
this_ty ty_float ty_super
1467 &&& simplify_subtype ~
subtype_env ~
this_ty ty_int
ty_super
1468 (* Likewise, reduce nullable on left to a union *)
1469 | (r, Toption
ty) ->
1470 let ty_null = MakeType.null
r in
1479 &&& simplify_subtype_i ~
subtype_env ~
this_ty (LoclType
ty) ety_super
1480 | (_
, Tintersection tyl
)
1481 when let (_
, non_ty_opt
, _
) =
1482 find_type_with_exact_negation env tyl
1484 Option.is_some non_ty_opt
->
1486 | (_
, Tintersection tyl_sub
) ->
1487 let simplify_super_intersection env tyl_sub
ty_super =
1488 (* It's sound to reduce t1 & t2 <: t to (t1 <: t) || (t2 <: t), but
1490 * TODO(T120921930): Don't do this if require_completeness is set.
1494 ~init
:(env
, TL.invalid ~
fail)
1495 ~f
:(fun res
ty_sub ->
1496 let ty_sub = LoclType
ty_sub in
1498 ||| simplify_subtype_i ~
subtype_env ~
this_ty ty_sub ty_super)
1500 (* Heuristicky logic to decide whether to "break" the intersection
1501 or the union first, based on observing that the following cases often occur:
1502 - A & B <: (A & B) | C
1503 In which case we want to "break" the union on the right first
1504 in order to have the following recursive calls :
1507 - A & (B | C) <: B | C
1508 In which case we want to "break" the intersection on the left first
1509 in order to have the following recursive calls:
1512 If there is a type variable in the union, then generally it's helpful to
1513 break the union apart.
1516 List.exists tyl_super ~f
:(fun t
->
1517 Typing_utils.is_tintersection env t
1518 || Typing_utils.is_tyvar env t
)
1520 simplify_sub_union env ety_sub tyl_super
1521 else if List.exists tyl_sub ~f
:(Typing_utils.is_tunion env
) then
1522 simplify_super_intersection env tyl_sub
(LoclType
ty_super)
1524 simplify_sub_union env ety_sub tyl_super
1525 | _
-> simplify_sub_union env ety_sub tyl_super
)))
1526 | (r_super, Toption arg_ty_super
) ->
1527 let (env
, ety
) = Env.expand_type env arg_ty_super
in
1528 (* Toption(Tnonnull) encodes mixed, which is our top type.
1529 * Everything subtypes mixed *)
1530 if is_nonnull ety
then
1534 | ConstraintType _
-> default_subtype env
1535 | LoclType lty_sub
->
1536 (match (deref lty_sub
, get_node ety
) with
1537 (* ?supportdyn<t> is equivalent to supportdyn<?t> *)
1538 | (_
, Tnewtype
(name
, [tyarg
], _
))
1539 when String.equal name
SN.Classes.cSupportDyn
->
1540 let tyarg = MakeType.nullable_locl
r_super tyarg in
1545 (mk
(r_super, Tnewtype
(name
, [tyarg], tyarg)))
1547 (* supportdyn<t> <: ?u iff
1548 * nonnull & supportdyn<t> <: u iff
1549 * supportdyn<nonnull & t> <: u
1551 | ((r_sub, Tnewtype
(name
, [tyarg1
], _
)), _
)
1552 when String.equal name
SN.Classes.cSupportDyn
->
1553 let (env
, ty_sub'
) =
1554 Inter.intersect env ~
r:r_super tyarg1
(MakeType.nonnull
r_super)
1556 let ty_sub'
= mk
(r_sub, Tnewtype
(name
, [ty_sub'
], ty_sub'
)) in
1557 simplify_subtype ~
subtype_env ~super_like
ty_sub' ety env
1558 (* A <: ?B iff A & nonnull <: B
1559 Only apply if B is a type variable or an intersection, to avoid oscillating
1560 forever between this case and the previous one. *)
1561 | ((_
, Tintersection tyl
), (Tintersection _
| Tvar _
))
1562 when let (_
, non_ty_opt
, _
) =
1563 find_type_with_exact_negation env tyl
1565 Option.is_none non_ty_opt
->
1566 let (env
, ty_sub'
) =
1567 Inter.intersect_i env
r_super ty_sub (MakeType.nonnull
r_super)
1573 (LoclType arg_ty_super
)
1575 (* null is the type of null and is a subtype of any option type. *)
1576 | ((_
, Tprim
Nast.Tnull
), _
) -> valid env
1577 (* ?ty_sub' <: ?ty_super' iff ty_sub' <: ?ty_super'. Reasoning:
1578 * If ?ty_sub' <: ?ty_super', then from ty_sub' <: ?ty_sub' (widening) and transitivity
1579 * of <: it follows that ty_sub' <: ?ty_super'. Conversely, if ty_sub' <: ?ty_super', then
1580 * by covariance and idempotence of ?, we have ?ty_sub' <: ??ty_sub' <: ?ty_super'.
1581 * Therefore, this step preserves the set of solutions.
1583 | ((_
, Toption
ty_sub'
), _
) ->
1591 (* We do not want to decompose Toption for these cases *)
1592 | ((_
, (Tvar _
| Tunion _
| Tintersection _
)), _
) ->
1594 | ((_
, Tgeneric _
), _
) when subtype_env.require_completeness
->
1595 (* TODO(T69551141) handle type arguments ? *)
1597 (* If t1 <: ?t2 and t1 is an abstract type constrained as t1',
1598 * then t1 <: t2 or t1' <: ?t2. The converse is obviously
1599 * true as well. We can fold the case where t1 is unconstrained
1600 * into the case analysis below.
1602 * In the case where it's easy to determine that null isn't in t1,
1603 * we need only check t1 <: t2.
1605 | ((_
, (Tnewtype _
| Tdependent _
| Tgeneric _
| Tprim
Nast.Tvoid
)), _
)
1607 (* TODO(T69551141) handle type arguments? *)
1608 if null_not_subtype lty_sub
then
1625 (* If ty_sub <: ?ty_super' and ty_sub does not contain null then we
1626 * must also have ty_sub <: ty_super'. The converse follows by
1627 * widening and transitivity. Therefore, this step preserves the set
1630 | ((_
, Tunapplied_alias _
), _
) ->
1631 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
1633 ( Tdynamic
| Tprim _
| Tnonnull
| Tfun _
| Ttuple _
| Tshape _
1634 | Tclass _
| Tvec_or_dict _
| Tany _
| Terr
| Taccess _
) ),
1643 (* This is treating the option as a union, and using the sound, but incomplete,
1644 t <: t1 | t2 to (t <: t1) || (t <: t2) reduction
1645 TODO(T120921930): Don't do this if require_completeness is set.
1647 | ((_
, Tneg _
), _
) ->
1656 | (_r_super
, Tdependent
(d_sup
, bound_sup
)) ->
1657 let (env
, bound_sup
) = Env.expand_type env bound_sup
in
1659 | ConstraintType _
-> default_subtype env
1660 | LoclType
ty_sub ->
1661 (match (deref
ty_sub, get_node bound_sup
) with
1662 | ((_
, Tclass _
), Tclass
((_
, x
), _
, _
))
1663 when is_final_and_invariant env x
->
1664 (* For final class C, there is no difference between `this as X` and `X`,
1665 * and `expr<#n> as X` and `X`.
1666 * But we need to take care with variant classes, since we can't
1667 * statically guarantee their runtime type.
1669 simplify_subtype ~
subtype_env ~
this_ty ty_sub bound_sup env
1670 | ( (r_sub, Tclass
((_
, y
), _
, _
)),
1671 Tclass
(((_
, x
) as id
), _
, _tyl_super
) ) ->
1673 if String.equal x y
then
1674 let p = Reason.to_pos
r_sub in
1675 let (pos_super
, class_name
) = id
in
1678 (Typing_error.Secondary.This_final
1679 { pos_super
; class_name
; pos_sub
= p }))
1683 invalid_env_with env
fail
1684 | ((_
, Tdependent
(d_sub
, bound_sub
)), _
) ->
1685 let this_ty = Option.first_some
this_ty (Some
ty_sub) in
1686 (* Dependent types are identical but bound might be different *)
1687 if equal_dependent_type d_sub d_sup
then
1688 simplify_subtype ~
subtype_env ~
this_ty bound_sub bound_sup env
1690 simplify_subtype ~
subtype_env ~
this_ty bound_sub
ty_super env
1691 | _
-> default_subtype env
))
1692 | (_
, Taccess _
) -> invalid_env env
1693 | (_
, Tgeneric
(name_super
, tyargs_super
)) ->
1694 (* TODO(T69551141) handle type arguments. Right now, only passing tyargs_super to
1695 Env.get_lower_bounds *)
1697 | ConstraintType _
-> default_subtype env
1698 (* If subtype and supertype are the same generic parameter, we're done *)
1699 | LoclType
ty_sub ->
1700 (match get_node
ty_sub with
1701 | Tgeneric
(name_sub
, tyargs_sub
) when String.equal name_sub name_super
1703 if List.is_empty tyargs_super
then
1706 (* TODO(T69931993) Type parameter env must carry variance information *)
1707 let variance_reifiedl =
1708 List.map tyargs_sub ~f
:(fun _
->
1709 (Ast_defs.Invariant
, Aast.Erased
))
1711 simplify_subtype_variance_for_non_injective
1720 (* When decomposing subtypes for the purpose of adding bounds on generic
1721 * parameters to the context, (so seen_generic_params = None), leave
1722 * subtype so that the bounds get added *)
1728 if subtype_env.require_completeness
then
1731 (* If we've seen this type parameter before then we must have gone
1732 * round a cycle so we fail
1735 VisitedGoals.try_add_visited_generic_super
1740 | None
-> invalid_env env
1741 | Some new_visited
->
1742 let subtype_env = { subtype_env with visited
= new_visited
} in
1743 (* Collect all the lower bounds ("super" constraints) on the
1744 * generic parameter, and check ty_sub against each of them in turn
1745 * until one of them succeeds *)
1746 let rec try_bounds tyl env
=
1748 | [] -> default_subtype env
1751 |> simplify_subtype ~
subtype_env ~
this_ty ty_sub ty
1754 (* Turn error into a generic error about the type parameter *)
1757 (Typing_set.elements
1758 (Env.get_lower_bounds env name_super tyargs_super
))
1759 |> if_unsat
invalid_env
1763 | ConstraintType cty
->
1765 match deref_constraint_type cty
with
1766 | (_
, (Thas_member _
| Tdestructure _
)) -> valid env
1767 | _
-> default_subtype env
1770 (match deref lty
with
1774 ( Tint
| Tbool
| Tfloat
| Tstring
| Tresource
| Tnum
1775 | Tarraykey
| Tnoreturn
))
1776 | Tnonnull
| Tfun _
| Ttuple _
| Tshape _
| Tclass _
1777 | Tvec_or_dict _
| Taccess _
) ) ->
1779 (* supportdyn<t> <: nonnull iff t <: nonnull *)
1780 | (_
, Tnewtype
(name
, [tyarg], _
))
1781 when String.equal name
SN.Classes.cSupportDyn
->
1782 env
|> simplify_subtype ~
subtype_env ~
this_ty tyarg ty_super
1783 (* negations always contain null *)
1784 | (_
, Tneg _
) -> invalid_env env
1785 | _
-> default_subtype env
))
1786 | (r_dynamic
, Tdynamic
)
1787 when TypecheckerOptions.enable_sound_dynamic env
.genv
.tcopt
1788 && (coercing_to_dynamic subtype_env
1789 || env
.in_support_dynamic_type_method_check
) ->
1790 let open Ast_defs
in
1792 | ConstraintType _cty
->
1795 | LoclType lty_sub
->
1796 let dyn = lazy (describe_ty_super ~
is_coeffect:false env ety_super
) in
1798 Lazy.map
dyn ~f
:(fun dyn ->
1799 Reason.to_string
("Expected " ^
dyn) r_dynamic
)
1800 and ty_name
= lazy (describe_ty_default env ety_sub
)
1801 and pos
= Reason.to_pos
(get_reason lty_sub
) in
1807 subtype_env.on_error
1811 apply_reasons ~on_error
1812 @@ Secondary.Not_sub_dynamic
1813 { pos
; ty_name
; dynamic_part })))
1817 (match deref lty_sub
with
1822 ( Tint
| Tbool
| Tfloat
| Tstring
| Tnum
| Tarraykey
| Tvoid
1823 | Tnoreturn
| Tresource
) ) ->
1825 | (_
, Tnewtype
(name_sub
, [_tyarg_sub
], _
))
1826 when String.equal name_sub
SN.Classes.cSupportDyn
->
1828 | (_
, Tnewtype
(name_sub
, _
, _
))
1829 when String.equal name_sub
SN.Classes.cEnumClassLabel
->
1831 | (_
, Toption
ty) ->
1832 (match deref
ty with
1833 (* Special case mixed <: dynamic for better error message *)
1834 | (_
, Tnonnull
) -> invalid_env env
1835 | _
-> simplify_subtype ~
subtype_env ty ty_super env
)
1836 | (_
, (Tdynamic
| Tprim Tnull
)) -> valid env
1838 | (_
, Tshape
(Open_shape
, _
))
1840 | (_
, Tunapplied_alias _
)
1845 | (_
, Tintersection _
)
1849 | (_
, Tvec_or_dict
(_
, ty)) ->
1850 simplify_subtype ~
subtype_env ty ty_super env
1851 | (_
, Tfun ft_sub
) ->
1852 if get_ft_support_dynamic_type ft_sub
then
1855 (* Special case of function type subtype dynamic.
1856 * (function(ty1,...,tyn):ty <: supportdyn<nonnull>)
1858 * dynamic <D: ty1 & ... & dynamic <D: tyn & ty <D: dynamic
1860 let ty_dyn_enf = { et_enforced
= Unenforced
; et_type
= ty_super } in
1862 (* Contravariant subtyping on parameters *)
1863 |> simplify_supertype_params_with_variadic
1867 &&& (* Finally do covariant subtryping on return type *)
1868 simplify_subtype ~
subtype_env ft_sub
.ft_ret
.et_type
ty_super
1869 | (_
, Ttuple tyl
) ->
1871 ~init
:(env
, TL.valid
)
1872 ~f
:(fun res
ty_sub ->
1873 res
&&& simplify_subtype ~
subtype_env ty_sub ty_super)
1875 | (_
, Tshape
(Closed_shape
, sftl
)) ->
1877 ~init
:(env
, TL.valid
)
1879 res
&&& simplify_subtype ~
subtype_env sft
.sft_ty
ty_super)
1880 (TShapeMap.values sftl
)
1881 | (_
, Tclass
((_
, class_id
), _exact
, tyargs
)) ->
1882 let class_def_sub = Typing_env.get_class env class_id
in
1883 (match class_def_sub with
1885 (* This should have been caught already in the naming phase *)
1889 Cls.get_support_dynamic_type class_sub
|| Env.is_enum env class_id
1891 (* If a class has the __SupportDynamicType annotation, then
1892 a type formed from it is a dynamic-aware subtype of dynamic if
1893 the type arguments are correctly supplied, which depends on the
1894 variance of the parameter, and whether the __RequireDynamic
1895 is on the parameter.
1897 let rec subtype_args tparams tyargs env
=
1898 match (tparams
, tyargs
) with
1902 | (tp
:: tparams
, tyarg :: tyargs
) ->
1903 let has_require_dynamic =
1905 SN.UserAttributes.uaRequireDynamic
1906 tp
.tp_user_attributes
1910 (* Implicit pessimisation should ignore the RequireDynamic attribute
1911 because everything should be pessimised enough that it isn't necessary. *)
1912 && not
(TypecheckerOptions.everything_sdt env
.genv
.tcopt
)
1914 (* If the class is marked <<__SupportDynamicType>> then for any
1915 * type parameters marked <<__RequireDynamic>> then the class does not
1916 * unconditionally implement dynamic, but rather we must check that
1917 * it is a subtype of the same type whose corresponding type arguments
1918 * are replaced by dynamic, intersected with the parameter's upper bounds.
1920 * For example, to check dict<int,float> <: supportdyn<nonnull>
1921 * we check dict<int,float> <D: dict<arraykey,dynamic>
1922 * which in turn requires int <D: arraykey and float <D: dynamic.
1925 List.filter_map tp
.tp_constraints ~f
:(fun (c
, ty) ->
1927 | Ast_defs.Constraint_as
->
1929 Phase.localize_no_subst env ~ignore_errors
:true ty
1935 MakeType.intersection r_dynamic
(ty_super :: upper_bounds)
1937 match tp
.tp_variance
with
1938 | Ast_defs.Covariant
->
1939 simplify_subtype ~
subtype_env tyarg super env
1940 | Ast_defs.Contravariant
->
1941 simplify_subtype ~
subtype_env super tyarg env
1942 | Ast_defs.Invariant
->
1943 simplify_subtype ~
subtype_env tyarg super env
1944 &&& simplify_subtype ~
subtype_env super tyarg
1946 (* If the class is marked <<__SupportDynamicType>> then for any
1947 * type parameters not marked <<__RequireDynamic>> then the class is a
1948 * subtype of dynamic only when the arguments are also subtypes of dynamic.
1950 match tp
.tp_variance
with
1951 | Ast_defs.Covariant
1952 | Ast_defs.Invariant
->
1953 simplify_subtype ~
subtype_env tyarg ty_super env
1954 | Ast_defs.Contravariant
->
1955 (* If the parameter is contra-variant, then we only need to
1956 check that the lower bounds (if present) are subtypes of
1957 dynamic. For example, given <<__SDT>> class C<-T> {...},
1958 then for any t, C<t> <: C<nothing>, and since
1959 `nothing <D: dynamic`, `C<nothing> <D: dynamic` and so
1960 `C<t> <D: dynamic`. If there are lower bounds, we can't
1961 push the argument below them. It suffices to check only
1962 them because if one of them is not <D: dynamic, then
1963 none of their supertypes are either.
1966 List.filter_map tp
.tp_constraints ~f
:(fun (c
, ty) ->
1968 | Ast_defs.Constraint_super
->
1970 Phase.localize_no_subst
1978 (match lower_bounds with
1981 let sub = MakeType.union r_dynamic
lower_bounds in
1982 simplify_subtype ~
subtype_env sub ty_super env
))
1983 &&& subtype_args tparams tyargs
1985 subtype_args (Cls.tparams class_sub
) tyargs env
1987 match Cls.kind class_sub
with
1988 | Ast_defs.Cenum_class _
->
1989 (match Cls.enum_type class_sub
with
1991 let ((env
, _ty_err_opt
), subtype
) =
1992 Typing_utils.localize_no_subst
1997 simplify_subtype ~
subtype_env subtype
ty_super env
1998 | None
-> default_subtype env
)
1999 | _
-> default_subtype env
2003 | LoclType lty
when is_dynamic lty
-> valid env
2006 default_subtype env
)
2007 | (_
, Tprim prim_ty
) ->
2009 | ConstraintType _
-> default_subtype env
2011 (match (deref lty
, prim_ty
) with
2012 | ((_
, Tprim
(Nast.Tint
| Nast.Tfloat
)), Nast.Tnum
) -> valid env
2013 | ((_
, Tprim
(Nast.Tint
| Nast.Tstring
)), Nast.Tarraykey
) -> valid env
2014 | ((_
, Tprim prim_sub
), _
) when Aast.equal_tprim prim_sub prim_ty
->
2016 | ((_
, Toption arg_ty_sub
), Nast.Tnull
) ->
2017 simplify_subtype ~
subtype_env ~
this_ty arg_ty_sub
ty_super env
2018 | (_
, _
) -> default_subtype env
))
2021 | ConstraintType cty
->
2023 match deref_constraint_type cty
with
2024 | (_
, (TCunion _
| TCintersection _
)) -> default_subtype env
2027 | LoclType
ty_sub ->
2028 (match deref
ty_sub with
2029 | (_
, Tany _
) -> valid env
2030 | (_
, (Tunion _
| Tintersection _
| Tvar _
)) -> default_subtype env
2031 | _
when subtype_env.no_top_bottom
-> default env
2033 | (r_super, Tfun ft_super
) ->
2035 | ConstraintType _
-> default_subtype env
2037 (match deref lty
with
2038 | (r_sub, Tfun ft_sub
) ->
2039 simplify_subtype_funs
2048 | _
-> default_subtype env
))
2049 | (_
, Ttuple tyl_super
) ->
2051 | ConstraintType _
-> default_subtype env
2052 (* (t1,...,tn) <: (u1,...,un) iff t1<:u1, ... , tn <: un *)
2054 (match get_node lty
with
2056 when Int.equal
(List.length tyl_super
) (List.length tyl_sub
) ->
2058 (fun res
ty_sub ty_super ->
2059 let ty_super = liken ~super_like env
ty_super in
2060 res
&&& simplify_subtype ~
subtype_env ty_sub ty_super)
2064 | _
-> default_subtype env
))
2065 | (r_super, Tshape
(shape_kind_super
, fdm_super
)) ->
2067 | ConstraintType _
-> default_subtype env
2069 let (sub_supportdyn'
, lty
) = strip_supportdyn lty
in
2070 (match deref lty
with
2071 | (r_sub, Tshape
(shape_kind_sub
, fdm_sub
)) ->
2072 simplify_subtype_shape
2077 (sub_supportdyn
|| sub_supportdyn'
, r_sub, shape_kind_sub
, fdm_sub
)
2078 (super_supportdyn
, r_super, shape_kind_super
, fdm_super
)
2079 | _
-> default_subtype env
))
2080 | (_
, Tvec_or_dict _
) ->
2082 | ConstraintType _
-> default_subtype env
2084 (match (get_node lty
, get_node
ty_super) with
2085 | (Tvec_or_dict
(tk_sub
, tv_sub
), Tvec_or_dict
(tk_super
, tv_super
)) ->
2086 let tv_super = liken ~super_like env
tv_super in
2087 let tk_super = liken ~super_like env
tk_super in
2089 |> simplify_subtype ~
subtype_env ~
this_ty tk_sub
tk_super
2090 &&& simplify_subtype ~
subtype_env ~
this_ty tv_sub
tv_super
2091 | ( Tclass
((_
, n
), _
, [tk_sub
; tv_sub
]),
2092 Tvec_or_dict
(tk_super, tv_super) )
2093 when String.equal n
SN.Collections.cDict
->
2094 let tv_super = liken ~super_like env
tv_super in
2095 let tk_super = liken ~super_like env
tk_super in
2097 |> simplify_subtype ~
subtype_env ~
this_ty tk_sub
tk_super
2098 &&& simplify_subtype ~
subtype_env ~
this_ty tv_sub
tv_super
2099 | (Tclass
((_
, n
), _
, [tv_sub
]), Tvec_or_dict
(tk_super, tv_super))
2100 when String.equal n
SN.Collections.cVec
->
2101 let pos = get_pos lty
in
2102 let tk_sub = MakeType.int (Reason.Ridx_vector_from_decl
pos) in
2103 let tv_super = liken ~super_like env
tv_super in
2104 let tk_super = liken ~super_like env
tk_super in
2106 |> simplify_subtype ~
subtype_env ~
this_ty tk_sub tk_super
2107 &&& simplify_subtype ~
subtype_env ~
this_ty tv_sub
tv_super
2108 | _
-> default_subtype env
))
2109 (* If t supports dynamic, and t <: u, then t <: supportdyn<u> *)
2110 | (r_supportdyn
, Tnewtype
(name_super
, [tyarg_super
], _
))
2111 when String.equal name_super
SN.Classes.cSupportDyn
->
2113 | ConstraintType _cty
->
2116 | LoclType lty_sub
->
2117 (match deref lty_sub
with
2118 | (_
, Tnewtype
(name_sub
, [tyarg_sub
], _
))
2119 when String.equal name_sub
SN.Classes.cSupportDyn
->
2125 ~super_supportdyn
:true
2126 ~sub_supportdyn
:true
2129 | (_
, (Tgeneric _
| Tvar _
)) -> default_subtype env
2131 let ty_dyn = MakeType.dynamic r_supportdyn
in
2137 ~super_supportdyn
:true
2140 &&& simplify_dynamic_aware_subtype
2145 | (_
, Tnewtype
(name_super
, tyl_super
, _
)) ->
2147 | ConstraintType _
-> default_subtype env
2149 (match deref lty
with
2150 | (_
, Tclass
((_
, name_sub
), _
, _
)) ->
2151 if String.equal name_sub name_super
&& Env.is_enum env name_super
then
2155 | (_
, Tnewtype
(name_sub
, tyl_sub
, _
))
2156 when String.equal name_sub name_super
->
2157 if List.is_empty tyl_sub
then
2159 else if Env.is_enum env name_super
&& Env.is_enum env name_sub
then
2162 let td = Env.get_typedef env name_super
in
2165 | Some
{ td_tparams
; _
} ->
2166 let variance_reifiedl =
2167 List.map td_tparams ~f
:(fun t
->
2168 (t
.tp_variance
, t
.tp_reified
))
2170 simplify_subtype_variance_for_non_injective
2180 | None
-> invalid_env env
2182 | _
-> default_subtype env
))
2183 | (_
, Tunapplied_alias n_sup
) ->
2185 | ConstraintType _
-> default_subtype env
2187 (match deref lty
with
2188 | (_
, Tunapplied_alias n_sub
) when String.equal n_sub n_sup
-> valid env
2189 | _
-> default_subtype env
))
2190 | (r_super, Tneg
(Neg_prim tprim_super
)) ->
2192 | ConstraintType _
-> default_subtype env
2193 | LoclType
ty_sub ->
2194 (match deref
ty_sub with
2195 | (r_sub, Tneg
(Neg_prim tprim_sub
)) ->
2199 (MakeType.prim_type
r_super tprim_super
)
2200 (MakeType.prim_type
r_sub tprim_sub
)
2202 | (_
, Tneg
(Neg_class _
)) ->
2203 (* not C contains all primitive types, and so can't be a subtype of
2204 not p, which doesn't contain primitive type p *)
2206 | (_
, Tprim tprim_sub
) ->
2207 if is_tprim_disjoint tprim_sub tprim_super
then
2211 | (_
, Tclass
((_
, cname
), ex
, _
))
2212 when String.equal cname
SN.Classes.cStringish
2215 equal_tprim tprim_super Tstring
2216 || equal_tprim tprim_super Tarraykey
) ->
2218 (* All of these are definitely disjoint from primitive types *)
2219 | (_
, (Tfun _
| Ttuple _
| Tshape _
| Tclass _
)) -> valid env
2220 | _
-> default_subtype env
))
2221 | (_
, Tneg
(Neg_class
(_
, c_super
))) ->
2223 | ConstraintType _
-> default_subtype env
2224 | LoclType
ty_sub ->
2225 (match deref
ty_sub with
2226 | (_
, Tneg
(Neg_class
(_
, c_sub
))) ->
2227 if Typing_utils.is_sub_class_refl env c_super c_sub
then
2231 | (_
, Tneg
(Neg_prim _
)) ->
2232 (* not p, for any primitive type p contains all class types, and so
2233 can't be a subtype of not c, which doesn't contain class types c *)
2235 | (_
, Tclass
((_
, c_sub
), _
, _
)) ->
2236 if is_class_disjoint env c_sub c_super
then
2240 (* All of these are definitely disjoint from class types *)
2241 | (_
, (Tfun _
| Ttuple _
| Tshape _
| Tprim _
)) -> valid env
2242 | _
-> default_subtype env
))
2243 | (r_super, Tclass
(x_super
, Nonexact cr_super
, tyl_super
))
2244 when (not
(Class_refinement.is_empty cr_super
))
2245 && (subtype_env.require_soundness
2246 || (* To deal with refinements, the code below generates a
2247 * constraint type. That is currently not supported when
2248 * require_soundness is not set (see below in the function
2249 * decompose_subtype_add_prop). Consequently, if soundness
2250 * is not required, we treat the refinement information
2251 * only if we know for sure that we can discharge it on
2252 * the spot; e.g., when ety_sub is a class-ish. This
2253 * limits the information lost by skipping refinements. *)
2254 TUtils.is_class_i ety_sub
) ->
2255 (* We discharge class refinements before anything
2257 Class_refinement.fold_type_refs
2260 ~f
:(fun type_id
(TRexact
ty) (env
, prop
) ->
2264 mk_constraint_type
(r_super, Thas_type_member
(type_id
, ty))
2271 (ConstraintType
htm_ty))
2273 (* ... then recursively check the class with all the
2274 * refinements dropped. *)
2275 let ty_super = mk
(r_super, Tclass
(x_super
, nonexact
, tyl_super
)) in
2282 | (_r_super
, Tclass
(((_
, class_name
) as x_super
), exact_super
, tyl_super
))
2285 | ConstraintType _
-> default_subtype env
2286 | LoclType
ty_sub ->
2287 (match deref
ty_sub with
2288 | (_
, Tnewtype
(enum_name
, _
, _
))
2289 when String.equal enum_name class_name
2290 && is_nonexact exact_super
2291 && Env.is_enum env enum_name
->
2293 | (_
, Tnewtype
(cid
, _
, _
))
2294 when String.equal class_name
SN.Classes.cHH_BuiltinEnum
2295 && Env.is_enum env cid
->
2296 (match tyl_super
with
2298 env
|> simplify_subtype ~
subtype_env ~
this_ty ty_sub ty_super'
2299 | _
-> default_subtype env
)
2300 | (_
, Tnewtype
(enum_name
, _
, _
))
2301 when String.equal enum_name class_name
&& Env.is_enum env enum_name
->
2303 | (_
, Tnewtype
(enum_name
, _
, _
))
2304 when Env.is_enum env enum_name
2305 && String.equal class_name
SN.Classes.cXHPChild
->
2307 | (_
, Tprim
Nast.(Tstring
| Tarraykey
| Tint
| Tfloat
| Tnum
))
2308 when String.equal class_name
SN.Classes.cXHPChild
2309 && is_nonexact exact_super
->
2311 | (_
, Tprim
Nast.Tstring
)
2312 when String.equal class_name
SN.Classes.cStringish
2313 && is_nonexact exact_super
->
2315 (* Match what's done in unify for non-strict code *)
2316 | (r_sub, Tclass
(x_sub
, exact_sub
, tyl_sub
)) ->
2317 let (cid_super
, cid_sub
) = (snd x_super
, snd x_sub
) in
2319 match (exact_sub
, exact_super
) with
2320 | (Nonexact _
, Exact
) -> false
2323 if String.equal cid_super cid_sub
then
2324 if List.is_empty tyl_sub
&& List.is_empty tyl_super
&& exact_match
2328 (* This is side-effecting as it registers a dependency *)
2329 let class_def_sub = Env.get_class env cid_sub
in
2330 (* If class is final then exactness is superfluous *)
2332 match class_def_sub with
2333 | Some tc
-> Cls.final tc
2336 if not
(exact_match || is_final) then
2339 (* We handle the case where a generic A<T> is used as A *)
2340 Int.( <> ) (List.length tyl_sub
) (List.length tyl_super
)
2342 let n_sub = List.length tyl_sub
in
2343 let n_super = List.length tyl_super
in
2347 subtype_env.on_error
2351 apply_reasons ~on_error
2352 @@ Secondary.Type_arity_mismatch
2356 decl_pos
= fst x_sub
;
2360 let variance_reifiedl =
2361 if List.is_empty tyl_sub
then
2364 match class_def_sub with
2366 List.map tyl_sub ~f
:(fun _
->
2367 (Ast_defs.Invariant
, Aast.Erased
))
2369 List.map
(Cls.tparams class_sub
) ~f
:(fun t
->
2370 (t
.tp_variance
, t
.tp_reified
))
2372 simplify_subtype_variance_for_injective
2380 else if not
exact_match then
2383 let class_def_sub = Env.get_class env cid_sub
in
2384 (match class_def_sub with
2386 (* This should have been caught already in the naming phase *)
2389 (* We handle the case where a generic A<T> is used as A *)
2392 empty_expand_env
with
2394 TUtils.make_locl_subst_for_class_tparams class_sub tyl_sub
;
2395 (* FIXME(T59448452): Unsound in general *)
2396 this_ty = Option.value this_ty ~
default:ty_sub;
2399 let up_obj = Cls.get_ancestor class_sub cid_super
in
2402 (* Since we have provided no `Typing_error.Reasons_callback.t`
2403 * in the `expand_env`, this will not generate any errors *)
2404 let ((env
, _ty_err_opt
), up_obj) =
2405 Phase.localize ~
ety_env env
up_obj
2416 Ast_defs.is_c_trait
(Cls.kind class_sub
)
2417 || Ast_defs.is_c_interface
(Cls.kind class_sub
)
2421 (Cls.all_ancestor_req_class_requirements class_sub
)
2424 let rec try_upper_bounds_on_this up_objs env
=
2427 (* It's crucial that we don't lose updates to tpenv in
2428 * env that were introduced by Phase.localize.
2429 * TODO: avoid this requirement *)
2431 | ub_obj_typ
:: up_objs
2432 when List.mem
reqs_class ub_obj_typ ~equal
:equal_decl_ty
2434 (* `require class` constraints do not induce subtyping,
2435 * so skipping them *)
2436 try_upper_bounds_on_this up_objs env
2437 | ub_obj_typ
:: up_objs
->
2438 (* A trait is never the runtime type, but it can be used
2439 * as a constraint if it has requirements or where
2440 * constraints for its using classes *)
2441 (* Since we have provided no `Typing_error.Reasons_callback.t`
2442 * in the `expand_env`, this will not generate any errors *)
2443 let ((env
, _ty_err_opt
), ub_obj_typ
) =
2444 Phase.localize ~
ety_env env ub_obj_typ
2450 (mk
(r_sub, get_node ub_obj_typ
))
2452 ||| try_upper_bounds_on_this up_objs
2454 try_upper_bounds_on_this
2455 (Cls.upper_bounds_on_this class_sub
)
2459 | (_r_sub
, Tvec_or_dict
(_
, tv
)) ->
2460 (match (exact_super
, tyl_super
) with
2461 | (Nonexact _
, [tv_super])
2462 when String.equal class_name
SN.Collections.cTraversable
2463 || String.equal class_name
SN.Collections.cContainer
->
2464 (* vec<tv> <: Traversable<tv_super>
2465 * iff tv <: tv_super
2466 * Likewise for vec<tv> <: Container<tv_super>
2467 * and map<_,tv> <: Traversable<tv_super>
2468 * and map<_,tv> <: Container<tv_super>
2470 simplify_subtype ~
subtype_env ~
this_ty tv
tv_super env
2471 | (Nonexact _
, [tk_super; tv_super])
2472 when String.equal class_name
SN.Collections.cKeyedTraversable
2473 || String.equal class_name
SN.Collections.cKeyedContainer
2474 || String.equal class_name
SN.Collections.cAnyArray
->
2475 (match get_node
ty_sub with
2476 | Tvec_or_dict
(tk
, _
) ->
2478 |> simplify_subtype ~
subtype_env ~
this_ty tk
tk_super
2479 &&& simplify_subtype ~
subtype_env ~
this_ty tv
tv_super
2480 | _
-> default_subtype env
)
2482 when String.equal class_name
SN.Collections.cKeyedTraversable
2483 || String.equal class_name
SN.Collections.cKeyedContainer
2484 || String.equal class_name
SN.Collections.cAnyArray
->
2485 (* All arrays are subtypes of the untyped KeyedContainer / Traversables *)
2487 | (_
, _
) -> default_subtype env
)
2488 | _
-> default_subtype env
)))
2490 and simplify_subtype_shape
2491 ~
(subtype_env : subtype_env)
2493 ~
(this_ty : locl_ty
option)
2494 ?
(super_like
= false)
2495 (supportdyn_sub
, r_sub, shape_kind_sub
, fdm_sub
)
2496 (supportdyn_super
, r_super, shape_kind_super
, fdm_super
) =
2498 Shape projection for shape type `s` and field `f` (`s |_ f`) is defined as:
2499 - if `f` appears in `s` as `f => ty` then `s |_ f` = `Required ty`
2500 - if `f` appears in `s` as `?f => ty` then `s |_ f` = `Optional ty`
2501 - if `f` does not appear in `s` and `s` is closed, then `s |_ f` = `Absent`
2502 - if `f` does not appear in `s` and `s` is open, then `s |_ f` = `Optional mixed`
2505 - `?f => nothing` should be ignored, and treated as `Absent`.
2506 Such a field cannot be given a value, and so is effectively not present.
2508 let shape_projection ~supportdyn field_name shape_kind shape_map
r =
2509 let make_supportdyn ty =
2513 (is_sub_type_for_union_i
2516 (LoclType
(MakeType.supportdyn
r (MakeType.mixed r))))
2518 MakeType.supportdyn
r ty
2523 match TShapeMap.find_opt field_name shape_map
with
2524 | Some
{ sft_ty
; sft_optional
} ->
2525 (match (deref sft_ty
, sft_optional
) with
2526 | ((_
, Tunion
[]), true) -> `Absent
2527 | (_
, true) -> `Optional
(make_supportdyn sft_ty
)
2528 | (_
, false) -> `Required
(make_supportdyn sft_ty
))
2531 match shape_kind
with
2533 let printable_name =
2534 TUtils.get_printable_shape_field_name field_name
2538 (Reason.Rmissing_optional_field
(Reason.to_pos
r, printable_name))
2540 `Optional
(make_supportdyn mixed_ty)
2541 | Closed_shape
-> `Absent
2545 For two particular projections `p1` and `p2`, `p1` <: `p2` iff:
2546 - `p1` = `Required ty1`, `p2` = `Required ty2`, and `ty1` <: `ty2`
2547 - `p1` = `Required ty1`, `p2` = `Optional ty2`, and `ty1` <: `ty2`
2548 - `p1` = `Optional ty1`, `p2` = `Optional ty2`, and `ty1` <: `ty2`
2549 - `p1` = `Absent`, `p2` = `Optional ty2`
2550 - `p1` = `Absent`, `p2` = `Absent`
2551 We therefore need to handle all other cases appropriately.
2553 let simplify_subtype_shape_projection
2554 (r_sub, proj_sub
) (r_super, proj_super
) field_name res
=
2555 let printable_name = TUtils.get_printable_shape_field_name field_name
in
2556 match (proj_sub
, proj_super
) with
2557 (***** "Successful" cases - 5 / 9 total cases *****)
2558 | (`Required sub_ty
, `Required super_ty
)
2559 | (`Required sub_ty
, `Optional super_ty
)
2560 | (`Optional sub_ty
, `Optional super_ty
) ->
2561 let super_ty = liken ~super_like env
super_ty in
2563 res
&&& simplify_subtype ~
subtype_env ~
this_ty sub_ty
super_ty
2564 | (`Absent
, `Optional _
)
2565 | (`Absent
, `Absent
) ->
2567 (***** Error cases - 4 / 9 total cases *****)
2568 | (`Required _
, `Absent
)
2569 | (`Optional _
, `Absent
) ->
2572 subtype_env.on_error
2576 apply_reasons ~on_error
2577 @@ Secondary.Missing_field
2579 pos = Reason.to_pos
r_super;
2580 decl_pos
= Reason.to_pos
r_sub;
2581 name
= printable_name;
2584 with_error
ty_err_opt res
2585 | (`Optional _
, `Required
super_ty) ->
2588 subtype_env.on_error
2592 apply_reasons ~on_error
2593 @@ Secondary.Required_field_is_optional
2595 pos = Reason.to_pos
r_sub;
2596 decl_pos
= Reason.to_pos
r_super;
2597 name
= printable_name;
2598 def_pos
= get_pos
super_ty;
2601 with_error
ty_err_opt res
2602 | (`Absent
, `Required _
) ->
2605 subtype_env.on_error
2609 apply_reasons ~on_error
2610 @@ Secondary.Missing_field
2612 decl_pos
= Reason.to_pos
r_super;
2613 pos = Reason.to_pos
r_sub;
2614 name
= printable_name;
2617 with_error
ty_err_opt res
2619 (* Helper function to project out a field and then simplify subtype *)
2620 let shape_project_and_simplify_subtype
2621 (supportdyn_sub
, r_sub, shape_kind_sub
, shape_map_sub
)
2622 (supportdyn_super
, r_super, shape_kind_super
, shape_map_super
)
2627 ~supportdyn
:supportdyn_sub
2635 ~supportdyn
:supportdyn_super
2641 simplify_subtype_shape_projection
2643 (r_super, proj_super)
2647 match (shape_kind_sub
, shape_kind_super
) with
2648 (* An open shape cannot subtype a closed shape *)
2649 | (Open_shape
, Closed_shape
) ->
2652 subtype_env.on_error
2656 apply_reasons ~on_error
2657 @@ Secondary.Shape_fields_unknown
2659 pos = Reason.to_pos
r_sub;
2660 decl_pos
= Reason.to_pos
r_super;
2664 (* Otherwise, all projections must subtype *)
2667 (shape_project_and_simplify_subtype
2668 (supportdyn_sub
, r_sub, shape_kind_sub
, fdm_sub
)
2669 (supportdyn_super
, r_super, shape_kind_super
, fdm_super
))
2670 (TShapeSet.of_list
(TShapeMap.keys fdm_sub
@ TShapeMap.keys fdm_super
))
2673 and simplify_subtype_can_index
2674 ~
subtype_env ~
this_ty ~
fail ty_sub ty_super (_r
, _ci
) env
=
2675 (* TODO: implement *)
2676 default_subtype ~
subtype_env ~
this_ty ~
fail env
ty_sub ty_super
2678 and simplify_subtype_can_traverse
2679 ~
subtype_env ~
this_ty ~
fail ty_sub ty_super ((_r
: Reason.t
), ct
) env
=
2683 ~function_name
:"simplify_subtype_can_traverse"
2688 | ConstraintType _
->
2689 default_subtype ~
subtype_env ~
this_ty ~
fail env
ty_sub ty_super
2690 | LoclType lty_sub
->
2691 (match get_node lty_sub
with
2693 simplify_subtype ~
subtype_env ~
this_ty lty_sub ct
.ct_val env
2695 (match ct
.ct_key
with
2697 | Some ct_key
-> simplify_subtype ~
subtype_env ~
this_ty lty_sub ct_key
)
2702 let trav_ty = can_traverse_to_iface ct
in
2703 simplify_subtype ~
subtype_env ~
this_ty lty_sub
trav_ty env
2704 | _
-> default_subtype ~
subtype_env ~
this_ty ~
fail env
ty_sub ty_super)
2706 and simplify_subtype_has_type_member
2707 ~
subtype_env ~
this_ty ~
fail ty_sub (r, memid
, memty
) env
=
2709 ConstraintType
(mk_constraint_type
(r, Thas_type_member
(memid
, memty
)))
2714 ~function_name
:"simplify_subtype_has_type_member"
2718 let (env
, ety_sub
) = Env.expand_internal_type env
ty_sub in
2719 let default_subtype env
=
2720 default_subtype ~
subtype_env ~
this_ty ~
fail env ety_sub
htmty
2723 | ConstraintType _
-> invalid ~
fail env
2724 | LoclType
ty_sub ->
2725 let concrete_rigid_tvar_access env ucckind bndtys
=
2726 (* First, we try to discharge the subtype query on the bound; if
2727 * that fails, we mint a fresh rigid type variable to represent
2728 * the concrete type constant and try to solve the query using it *)
2729 let ( ||| ) = ( ||| ) ~
fail in
2730 let bndty = MakeType.intersection
(get_reason
ty_sub) bndtys
in
2731 simplify_subtype_i ~
subtype_env ~
this_ty (LoclType
bndty) htmty env
2733 (* TODO(refinements): The treatment of `this_ty` below is
2734 * no good; see below. *)
2735 let (env
, dtmemty
) =
2736 Typing_type_member.make_type_member
2738 ~
this_ty:(Option.value this_ty ~
default:ty_sub)
2739 ~on_error
:subtype_env.on_error
2742 (Reason.to_pos
r, memid
)
2744 simplify_subtype ~
subtype_env ~
this_ty dtmemty memty env
2745 &&& simplify_subtype ~
subtype_env ~
this_ty memty dtmemty
2747 (match deref
ty_sub with
2748 | (_r_sub
, Tclass
(x_sub
, exact_sub
, _tyl_sub
)) ->
2749 let (env
, type_member
) =
2750 (* TODO(refinements): The treatment of `this_ty` below is
2751 * no good; we should not default to `ty_sub`. `this_ty`
2752 * will be used when a type constant refers to another
2753 * constant either in its def or in its bounds.
2754 * See related FIXME(T59448452) above. *)
2755 Typing_type_member.lookup_class_type_member
2757 ~
this_ty:(Option.value this_ty ~
default:ty_sub)
2758 ~on_error
:subtype_env.on_error
2760 (Reason.to_pos
r, memid
)
2762 (match type_member
with
2763 | Typing_type_member.Error err
-> invalid ~
fail:err env
2764 | Typing_type_member.Exact
ty ->
2765 let this_ty = None
in
2766 simplify_subtype ~
subtype_env ~
this_ty ty memty env
2767 &&& simplify_subtype ~
subtype_env ~
this_ty memty
ty
2768 | Typing_type_member.Abstract _
-> invalid ~
fail env
)
2769 | (_r_sub
, Tdependent
(DTexpr eid
, bndty)) ->
2770 concrete_rigid_tvar_access env
(Typing_type_member.EDT eid
) [bndty]
2771 | (_r_sub
, Tgeneric
(s
, ty_args
))
2772 when String.equal s
Naming_special_names.Typehints.this
->
2773 let bnd_tys = Typing_set.elements
(Env.get_upper_bounds env s ty_args
) in
2774 concrete_rigid_tvar_access env
Typing_type_member.This
bnd_tys
2775 | (_
, (Tvar _
| Tgeneric _
| Tunion _
| Tintersection _
| Terr
)) ->
2777 | _
-> invalid ~
fail env
)
2779 and simplify_subtype_has_member
2783 ?
(nullsafe
: Reason.t
option)
2787 let using_new_method_call_inference =
2788 TypecheckerOptions.method_call_inference
(Env.get_tcopt env
)
2791 hm_name
= (name_pos
, name_
) as name
;
2792 hm_type
= member_ty
;
2793 hm_class_id
= class_id
;
2794 hm_explicit_targs
= explicit_targs
;
2798 let is_method = Option.is_some explicit_targs
in
2799 (* If `nullsafe` is `Some _`, we are allowing the object type on LHS to be nullable. *)
2800 let mk_maybe_nullable env
ty =
2804 let null_ty = MakeType.null
r_null in
2805 Typing_union.union_i env
r_null ty null_ty
2807 let (env
, maybe_nullable_ty_super
) =
2808 let ty_super = mk_constraint_type
(r, Thas_member has_member_ty
) in
2809 mk_maybe_nullable env
(ConstraintType
ty_super)
2815 ~function_name
:"simplify_subtype_has_member"
2818 maybe_nullable_ty_super
;
2819 let (env
, ety_sub
) = Env.expand_internal_type env
ty_sub in
2820 let default_subtype env
=
2827 maybe_nullable_ty_super
2830 | ConstraintType cty
->
2831 (match deref_constraint_type cty
with
2837 hm_class_id
= cid_sub
;
2838 hm_explicit_targs
= explicit_targs_sub
;
2841 let targ_equal (_
, (_
, hint1
)) (_
, (_
, hint2
)) =
2842 Aast_defs.equal_hint_ hint1 hint2
2844 String.equal
(snd name_sub
) name_
2845 && class_id_equal cid_sub class_id
2847 (List.equal
targ_equal)
2851 simplify_subtype ~
subtype_env ~
this_ty ty_sub member_ty env
2854 | _
-> default_subtype env
)
2855 | LoclType
ty_sub ->
2856 (match deref
ty_sub with
2857 | (_
, (Tvar _
| Tunion _
| Terr
)) -> default_subtype env
2858 | (r_null, Tprim
Aast.Tnull
) when using_new_method_call_inference ->
2859 if Option.is_some nullsafe
then
2868 @@ Primary.Null_member
2871 member_name
= name_
;
2873 lazy (Reason.to_string
"This can be null" r_null);
2881 | (r_option
, Toption option_ty
) when using_new_method_call_inference ->
2882 if Option.is_some nullsafe
then
2883 simplify_subtype_has_member
2888 (LoclType option_ty
)
2892 let (env
, option_ty
) = Env.expand_type env option_ty
in
2893 (match get_node option_ty
with
2901 @@ Primary.Top_member
2912 decl_pos
= Reason.to_pos r_option
;
2913 ty_name
= lazy (Typing_print.error env
ty_sub);
2914 (* Subtyping already gives these reasons *)
2915 ty_reasons
= lazy [];
2924 @@ Primary.Null_member
2927 member_name
= name_
;
2929 lazy (Reason.to_string
"This can be null" r_option
);
2937 | (_
, Tintersection tyl
)
2938 when let (_
, non_ty_opt
, _
) = find_type_with_exact_negation env tyl
in
2939 Option.is_some non_ty_opt
->
2940 (* use default_subtype to perform: A & B <: C <=> A <: C | !B *)
2942 | (r_inter
, Tintersection
[]) ->
2943 (* Tintersection [] = mixed *)
2950 @@ Primary.Top_member
2961 decl_pos
= Reason.to_pos r_inter
;
2962 ty_name
= lazy (Typing_print.error env
ty_sub);
2963 (* Subtyping already gives these reasons *)
2964 ty_reasons
= lazy [];
2966 | (r_inter
, Tintersection tyl
) when using_new_method_call_inference ->
2967 let (env
, tyl
) = List.map_env ~f
:Env.expand_type env tyl
in
2968 let subtype_fresh_has_member_ty env
ty_sub =
2969 let (env
, fresh_tyvar
) = Env.fresh_type env name_pos
in
2970 let env = Env.set_tyvar_variance
env fresh_tyvar
in
2971 let fresh_has_member_ty =
2973 (r, Thas_member
{ has_member_ty
with hm_type
= fresh_tyvar
})
2975 let (env, maybe_nullable_fresh_has_member_ty
) =
2976 mk_maybe_nullable env (ConstraintType
fresh_has_member_ty)
2978 let (env, ty_err_opt) =
2984 maybe_nullable_fresh_has_member_ty
2986 match ty_err_opt with
2988 let (env, _ty_err_opt
) =
2989 match get_var fresh_tyvar
with
2991 (* TODO: can this actually generate an error? *)
2992 Typing_solver.solve_to_equal_bound_or_wrt_variance
2996 | None
-> (env, None
)
2998 ((env, None
), Some fresh_tyvar
)
2999 | Some _
-> ((env, ty_err_opt), None
)
3001 let ((env, ty_err_opt), fresh_tyvar_opts
) =
3002 TUtils.run_on_intersection_with_ty_err
3005 ~f
:subtype_fresh_has_member_ty
3007 let fresh_tyvars = List.filter_map ~f
:Fn.id fresh_tyvar_opts
in
3008 if List.is_empty
fresh_tyvars then
3009 invalid ~
fail:ty_err_opt env
3011 let (env, intersection_ty
) =
3012 Inter.intersect_list
env r_inter
fresh_tyvars
3014 simplify_subtype ~
subtype_env ~
this_ty intersection_ty member_ty
env
3015 | (_
, Tnewtype
(_
, _
, newtype_ty
)) ->
3016 simplify_subtype_has_member
3021 (LoclType newtype_ty
)
3025 | (_, Tdependent _) ->
3026 | (_, Tgeneric _) ->
3029 let explicit_targs =
3030 match explicit_targs with
3032 | Some targs
-> targs
3034 let (res
, (obj_get_ty
, _tal
)) =
3035 Typing_object_get.obj_get
3040 ~coerce_from_ty
:None
3045 ~on_error
:Typing_error.Callback.unify_error
3051 | (env, None
) -> valid
env
3052 | (env, Some ty_err
) ->
3053 (* TODO - this needs to somehow(?) account for the fact that the old
3054 code considered FIXMEs in this position *)
3057 subtype_env.on_error
3061 apply_reasons ~on_error
@@ Secondary.Of_error ty_err
)
3066 prop &&& simplify_subtype ~
subtype_env ~
this_ty obj_get_ty member_ty
)
3068 (* Given an injective type constructor C (e.g., a class)
3069 * C<t1, .., tn> <: C<u1, .., un> iff
3070 * t1 <:v1> u1 /\ ... /\ tn <:vn> un
3071 * where vi is the variance of the i'th generic parameter of C,
3072 * and <:v denotes the appropriate direction of subtyping for variance v *)
3073 and simplify_subtype_variance_for_injective
3074 ~
(subtype_env : subtype_env)
3075 ?
(super_like
= false)
3077 (variance_reifiedl : (Ast_defs.variance
* Aast.reify_kind
) list
)
3078 (children_tyl
: locl_ty list
)
3079 (super_tyl
: locl_ty list
) : env -> env * TL.subtype_prop
=
3081 let simplify_subtype reify_kind
=
3082 (* When doing coercions from dynamic we treat dynamic as a bottom type. This is generally
3083 correct, except for the case when the generic isn't erased. When a generic is
3084 reified it is enforced as if it is it's own separate class in the runtime. i.e.
3087 class Box<reify T> {}
3088 function box_int(): Box<int> { return new Box<~int>(); }
3090 If is enforced like:
3091 class Box<reify T> {}
3092 class Box_int extends Box<int> {}
3093 class Box_like_int extends Box<~int> {}
3095 function box_int(): Box_int { return new Box_like_int(); }
3097 Thus we cannot push the like type to the outside of generic like we can
3102 (not
Aast.(equal_reify_kind reify_kind Erased
))
3103 && coercing_from_dynamic subtype_env
3105 { subtype_env with coerce
= None
}
3109 simplify_subtype ~
subtype_env ~
this_ty:None
3111 let simplify_subtype_variance_for_injective =
3112 simplify_subtype_variance_for_injective ~
subtype_env ~super_like
3114 match (variance_reifiedl, children_tyl
, super_tyl
) with
3119 | ( (variance
, reify_kind
) :: variance_reifiedl,
3121 super :: superl
) ->
3122 let simplify_subtype = simplify_subtype reify_kind
in
3125 | Ast_defs.Covariant
->
3126 let super = liken ~super_like
env super in
3127 simplify_subtype child
super env
3128 | Ast_defs.Contravariant
->
3131 ( Reason.Rcontravariant_generic
(get_reason
super, cid
),
3134 simplify_subtype super child
env
3135 | Ast_defs.Invariant
->
3137 mk
(Reason.Rinvariant_generic
(get_reason
super, cid
), get_node
super)
3140 |> simplify_subtype child
(liken ~super_like
env super'
)
3141 &&& simplify_subtype super' child
3143 &&& simplify_subtype_variance_for_injective
3149 (* Given a type constructor N that may not be injective (e.g., a newtype)
3150 * t1 <:v1> u1 /\ ... /\ tn <:vn> un
3152 * N<t1, .., tn> <: N<u1, .., un>
3153 * where vi is the variance of the i'th generic parameter of N,
3154 * and <:v denotes the appropriate direction of subtyping for variance v.
3155 * However, the reverse direction does not hold. *)
3156 and simplify_subtype_variance_for_non_injective
3157 ~
(subtype_env : subtype_env)
3160 (variance_reifiedl : (Ast_defs.variance
* Aast.reify_kind
) list
)
3161 (children_tyl
: locl_ty list
)
3162 (super_tyl
: locl_ty list
)
3166 let ((env, p) as res
) =
3167 simplify_subtype_variance_for_injective
3176 if subtype_env.require_completeness
&& not
(TL.is_valid
p) then
3177 (* If we require completeness, then we can still use the incomplete
3178 * N<t1, .., tn> <: N<u1, .., un> to t1 <:v1> u1 /\ ... /\ tn <:vn> un
3179 * simplification if all of the latter constraints already hold.
3180 * If they don't already hold, there is nothing we can (soundly) simplify. *)
3181 if subtype_env.require_soundness
then
3182 (env, mk_issubtype_prop ~coerce
:subtype_env.coerce
env ty_sub ty_super)
3188 and simplify_subtype_params
3189 ~
(subtype_env : subtype_env)
3190 ?
(check_params_ifc
= false)
3191 (subl
: locl_fun_param list
)
3192 (superl
: locl_fun_param list
)
3193 (variadic_sub_ty
: bool)
3194 (variadic_super_ty
: bool)
3196 let simplify_subtype_possibly_enforced =
3197 simplify_subtype_possibly_enforced ~
subtype_env
3199 let simplify_subtype_params = simplify_subtype_params ~
subtype_env in
3200 let simplify_subtype_params_with_variadic =
3201 simplify_subtype_params_with_variadic ~
subtype_env
3203 let simplify_supertype_params_with_variadic =
3204 simplify_supertype_params_with_variadic ~
subtype_env
3206 match (subl
, superl
) with
3207 (* When either list runs out, we still have to typecheck that
3208 the remaining portion sub/super types with the other's variadic.
3211 public function a(int $x = 0, string ... $args) // superl = [int], super_var = string
3215 public function a(string ... $args) // subl = [], sub_var = string
3217 , there should be an error because the first argument will be checked against
3218 int, not string that is, ChildClass::a("hello") would crash,
3219 but ParentClass::a("hello") wouldn't.
3221 Similarly, if the other list is longer, aka
3222 ChildClass extends ParentClass {
3223 public function a(mixed ... $args) // superl = [], super_var = mixed
3227 //subl = [string], sub_var = string
3228 public function a(string $x = 0, string ... $args)
3230 It should also check that string is a subtype of mixed.
3232 | ([fp
], _
) when variadic_sub_ty
->
3233 simplify_supertype_params_with_variadic superl fp
.fp_type
env
3234 | (_
, [fp
]) when variadic_super_ty
->
3235 simplify_subtype_params_with_variadic subl fp
.fp_type
env
3236 | ([], _
) -> valid
env
3237 | (_
, []) -> valid
env
3238 | (sub :: subl
, super :: superl
) ->
3239 let { fp_type
= ty_sub; _
} = sub in
3240 let { fp_type
= ty_super; _
} = super in
3241 (* Check that the calling conventions of the params are compatible. *)
3243 |> simplify_param_modes ~
subtype_env sub super
3244 &&& simplify_param_readonly ~
subtype_env sub super
3245 &&& simplify_param_accept_disposable ~
subtype_env sub super
3247 if check_params_ifc
then
3248 simplify_param_ifc ~
subtype_env sub super
3254 match (get_fp_mode
sub, get_fp_mode
super) with
3255 | (FPinout
, FPinout
) ->
3256 (* Inout parameters are invariant wrt subtyping for function types. *)
3258 |> simplify_subtype_possibly_enforced ty_super ty_sub
3259 &&& simplify_subtype_possibly_enforced ty_sub ty_super
3260 | _
-> env |> simplify_subtype_possibly_enforced ty_sub ty_super
3262 &&& simplify_subtype_params subl superl variadic_sub_ty variadic_super_ty
3264 and simplify_subtype_params_with_variadic
3265 ~
(subtype_env : subtype_env)
3266 (subl
: locl_fun_param list
)
3267 (variadic_ty
: locl_possibly_enforced_ty
)
3269 let simplify_subtype_possibly_enforced =
3270 simplify_subtype_possibly_enforced ~
subtype_env
3272 let simplify_subtype_params_with_variadic =
3273 simplify_subtype_params_with_variadic ~
subtype_env
3277 | { fp_type
= sub; _
} :: subl
->
3279 |> simplify_subtype_possibly_enforced sub variadic_ty
3280 &&& simplify_subtype_params_with_variadic subl variadic_ty
3282 and simplify_subtype_implicit_params
3283 ~
subtype_env { capability
= sub_cap
} { capability
= super_cap
} env =
3284 if TypecheckerOptions.any_coeffects
(Env.get_tcopt
env) then
3285 let expected = Typing_coeffects.get_type sub_cap
in
3286 let got = Typing_coeffects.get_type super_cap
in
3288 Typing_error.Secondary.Coeffect_subtyping
3291 cap
= Typing_coeffects.pretty
env got;
3292 pos_expected
= get_pos
expected;
3293 cap_expected
= Typing_coeffects.pretty
env expected;
3297 Option.map
subtype_env.on_error ~f
:(fun on_error ->
3298 let err = Typing_error.apply_reasons ~
on_error reasons in
3299 Typing_error.(Reasons_callback.always
err))
3301 let subtype_env = { subtype_env with on_error } in
3302 match (sub_cap
, super_cap
) with
3303 | (CapTy
sub, CapTy
super) -> simplify_subtype ~
subtype_env sub super env
3304 | (CapTy
sub, CapDefaults _p
) -> simplify_subtype ~
subtype_env sub got env
3305 | (CapDefaults _p
, CapTy
super) ->
3306 simplify_subtype ~
subtype_env expected super env
3307 | (CapDefaults _p1
, CapDefaults _p2
) -> valid
env
3311 and simplify_supertype_params_with_variadic
3312 ~
(subtype_env : subtype_env)
3313 (superl
: locl_fun_param list
)
3314 (variadic_ty
: locl_possibly_enforced_ty
)
3316 let simplify_subtype_possibly_enforced =
3317 simplify_subtype_possibly_enforced ~
subtype_env
3319 let simplify_supertype_params_with_variadic =
3320 simplify_supertype_params_with_variadic ~
subtype_env
3324 | { fp_type
= super; _
} :: superl
->
3326 |> simplify_subtype_possibly_enforced variadic_ty
super
3327 &&& simplify_supertype_params_with_variadic superl variadic_ty
3329 and simplify_param_modes ~
subtype_env param1 param2
env =
3330 let { fp_pos
= pos1
; _
} = param1
in
3331 let { fp_pos
= pos2
; _
} = param2
in
3332 match (get_fp_mode param1
, get_fp_mode param2
) with
3333 | (FPnormal
, FPnormal
)
3334 | (FPinout
, FPinout
) ->
3336 | (FPnormal
, FPinout
) ->
3340 subtype_env.on_error
3344 apply_reasons ~
on_error
3345 @@ Secondary.Inoutness_mismatch
{ pos = pos2
; decl_pos
= pos1
}))
3347 | (FPinout
, FPnormal
) ->
3351 subtype_env.on_error
3355 apply_reasons ~
on_error
3356 @@ Secondary.Inoutness_mismatch
{ pos = pos1
; decl_pos
= pos2
}))
3359 and simplify_param_accept_disposable ~
subtype_env param1 param2
env =
3360 let { fp_pos
= pos1
; _
} = param1
in
3361 let { fp_pos
= pos2
; _
} = param2
in
3362 match (get_fp_accept_disposable param1
, get_fp_accept_disposable param2
) with
3367 subtype_env.on_error
3371 apply_reasons ~
on_error
3372 @@ Secondary.Accept_disposable_invariant
3373 { pos = pos1
; decl_pos
= pos2
}))
3379 subtype_env.on_error
3383 apply_reasons ~
on_error
3384 @@ Secondary.Accept_disposable_invariant
3385 { pos = pos2
; decl_pos
= pos1
}))
3387 | (_
, _
) -> valid
env
3389 and simplify_param_ifc ~
subtype_env sub super env =
3390 let { fp_pos
= pos_sub
; _
} = sub in
3391 let { fp_pos
= pos_super
; _
} = super in
3392 (* TODO: also handle <<CanCall>> *)
3393 match (get_fp_ifc_external
sub, get_fp_ifc_external
super) with
3398 subtype_env.on_error
3402 apply_reasons ~
on_error
3403 @@ Secondary.Ifc_external_contravariant
{ pos_super
; pos_sub
}))
3407 and simplify_param_readonly ~
subtype_env sub super env =
3408 (* The sub param here (as with all simplify_param_* functions)
3409 is actually the parameter on ft_super, since params are contravariant *)
3410 (* Thus we check readonly subtyping covariantly *)
3411 let { fp_pos
= pos1
; _
} = sub in
3412 let { fp_pos
= pos2
; _
} = super in
3413 if not
(readonly_subtype
(get_fp_readonly
sub) (get_fp_readonly
super)) then
3417 subtype_env.on_error
3421 apply_reasons ~
on_error
3422 @@ Secondary.Readonly_mismatch
3426 reason_sub
= lazy [(pos2
, "This parameter is mutable")];
3428 lazy [(pos1
, "But this parameter is readonly")];
3434 and ifc_policy_matches
(ifc1
: ifc_fun_decl
) (ifc2
: ifc_fun_decl
) =
3435 match (ifc1
, ifc2
) with
3436 | (FDPolicied
(Some s1
), FDPolicied
(Some s2
)) when String.equal s1 s2
-> true
3437 | (FDPolicied None
, FDPolicied None
) -> true
3438 (* TODO(T79510128): IFC needs to check that the constraints inferred by the parent entail those by the subtype *)
3439 | (FDInferFlows
, FDInferFlows
) -> true
3442 and readonly_subtype
(r_sub : bool) (r_super : bool) =
3443 match (r_sub, r_super) with
3445 false (* A readonly value is a supertype of a mutable one *)
3448 (* Helper function for subtyping on function types: performs all checks that
3449 * don't involve actual types:
3450 * <<__ReturnDisposable>> attribute
3452 * <<__Policied>> attribute
3455 and simplify_subtype_funs_attributes
3458 (ft_sub
: locl_fun_type
)
3459 (r_super : Reason.t
)
3460 (ft_super
: locl_fun_type
)
3462 let p_sub = Reason.to_pos
r_sub in
3463 let p_super = Reason.to_pos
r_super in
3464 let ifc_policy_err_str = function
3465 | FDPolicied
(Some s
) -> s
3466 | FDPolicied None
-> "the existential policy"
3467 | FDInferFlows
-> "an inferred policy"
3471 (ifc_policy_matches ft_sub
.ft_ifc_decl ft_super
.ft_ifc_decl
)
3473 subtype_env.on_error
3477 apply_reasons ~
on_error
3478 @@ Secondary.Ifc_policy_mismatch
3481 policy
= ifc_policy_err_str ft_sub
.ft_ifc_decl
;
3482 pos_super
= p_super;
3483 policy_super
= ifc_policy_err_str ft_super
.ft_ifc_decl
;
3487 (* Readonly this is contravariant, so check ft_super_ro <: ft_sub_ro *)
3488 (get_ft_readonly_this ft_super
)
3489 (get_ft_readonly_this ft_sub
))
3491 subtype_env.on_error
3495 apply_reasons ~
on_error
3496 @@ Secondary.Readonly_mismatch
3501 lazy [(p_sub, "This function is not marked readonly")];
3503 lazy [(p_super, "This function is marked readonly")];
3507 (* Readonly return is covariant, so check ft_sub <: ft_super *)
3508 (get_ft_returns_readonly ft_sub
)
3509 (get_ft_returns_readonly ft_super
))
3511 subtype_env.on_error
3515 apply_reasons ~
on_error
3516 @@ Secondary.Readonly_mismatch
3522 [(p_sub, "This function returns a readonly value")];
3527 "This function does not return a readonly value"
3533 (get_ft_return_disposable ft_sub
)
3534 (get_ft_return_disposable ft_super
))
3536 subtype_env.on_error
3540 apply_reasons ~
on_error
3541 @@ Secondary.Return_disposable_mismatch
3543 pos_super
= p_super;
3545 is_marked_return_disposable
=
3546 get_ft_return_disposable ft_super
;
3549 (arity_min ft_sub
<= arity_min ft_super
)
3551 subtype_env.on_error
3555 apply_reasons ~
on_error
3556 @@ Secondary.Fun_too_many_args
3558 expected = arity_min ft_super
;
3559 actual
= arity_min ft_sub
;
3564 let ft_sub_variadic =
3565 if get_ft_variadic ft_sub
then
3566 List.last ft_sub
.ft_params
3570 let ft_super_variadic =
3571 if get_ft_variadic ft_super
then
3572 List.last ft_super
.ft_params
3577 match (ft_sub_variadic, ft_super_variadic) with
3578 | (Some
{ fp_name
= None
; _
}, Some
{ fp_name
= Some _
; _
}) ->
3579 (* The HHVM runtime ignores "..." entirely, but knows about
3580 * "...$args"; for contexts for which the runtime enforces method
3581 * compatibility (currently, inheritance from abstract/interface
3582 * methods), letting "..." override "...$args" would result in method
3583 * compatibility errors at runtime. *)
3586 subtype_env.on_error
3590 apply_reasons ~
on_error
3591 @@ Secondary.Fun_variadicity_hh_vs_php56
3592 { pos = p_sub; decl_pos
= p_super }))
3595 let sub_max = List.length ft_sub
.ft_params
in
3596 let super_max = List.length ft_super
.ft_params
in
3597 if sub_max < super_max then
3600 subtype_env.on_error
3604 apply_reasons ~
on_error
3605 @@ Secondary.Fun_too_few_args
3609 expected = super_max;
3618 subtype_env.on_error
3622 apply_reasons ~
on_error
3623 @@ Secondary.Fun_unexpected_nonvariadic
3624 { pos = p_sub; decl_pos
= p_super }))
3628 and simplify_subtype_possibly_enforced
3629 ~
(subtype_env : subtype_env) et_sub et_super
=
3630 simplify_subtype ~
subtype_env et_sub
.et_type et_super
.et_type
3632 (* This implements basic subtyping on non-generic function types:
3633 * (1) return type behaves covariantly
3634 * (2) parameter types behave contravariantly
3635 * (3) special casing for variadics
3637 and simplify_subtype_funs
3638 ~
(subtype_env : subtype_env)
3639 ~
(check_return
: bool)
3640 ?
(super_like
= false)
3642 (ft_sub
: locl_fun_type
)
3643 (r_super : Reason.t
)
3644 (ft_super
: locl_fun_type
)
3645 env : env * TL.subtype_prop
=
3646 (* First apply checks on attributes and variadic arity *)
3647 let simplify_subtype_implicit_params =
3648 simplify_subtype_implicit_params ~
subtype_env
3651 |> simplify_subtype_funs_attributes ~
subtype_env r_sub ft_sub
r_super ft_super
3652 &&& (* Now do contravariant subtyping on parameters *)
3654 (* If both fun policies are IFC public, there's no need to check for inheritance issues *)
3655 (* There is the chance that the super function has an <<__External>> argument and the sub function does not,
3656 but <<__External>> on a public policied function literally just means the argument must be governed by the public policy,
3657 so should be an error in any case.
3659 let check_params_ifc =
3660 non_public_ifc ft_super
.ft_ifc_decl
|| non_public_ifc ft_sub
.ft_ifc_decl
3662 simplify_subtype_params
3667 (get_ft_variadic ft_super
)
3668 (get_ft_variadic ft_sub
)
3670 &&& simplify_subtype_implicit_params
3671 ft_super
.ft_implicit_params
3672 ft_sub
.ft_implicit_params
3674 (* Finally do covariant subtyping on return type *)
3675 if check_return
then
3676 let super_ty = liken ~super_like
env ft_super
.ft_ret
.et_type
in
3677 simplify_subtype ~
subtype_env ft_sub
.ft_ret
.et_type
super_ty
3681 (* Add a new upper bound ty on var. Apply transitivity of sutyping,
3682 * so if we already have tyl <: var, then check that for each ty_sub
3683 * in tyl we have ty_sub <: ty.
3685 and add_tyvar_upper_bound_and_close
3690 (on_error : Typing_error.Reasons_callback.t
option) =
3693 | LoclType
ty -> LoclType
(transform_dynamic_upper_bound ~coerce
env ty)
3696 let upper_bounds_before = Env.get_tyvar_upper_bounds
env var
in
3698 Env.add_tyvar_upper_bound_and_update_variances
3699 ~intersect
:(try_intersect_i ~ignore_tyvars
:true env)
3704 let upper_bounds_after = Env.get_tyvar_upper_bounds
env var
in
3705 let added_upper_bounds = ITySet.diff
upper_bounds_after upper_bounds_before in
3706 let lower_bounds = Env.get_tyvar_lower_bounds
env var
in
3709 (fun upper_bound
(env, prop) ->
3710 let (env, ty_err_opt) =
3711 Typing_subtype_tconst.make_all_type_consts_equal
3716 ~as_tyvar_with_cnstr
:true
3720 ~
default:(env, prop)
3721 ~f
:(fun ty_err
-> invalid ~
fail:(Some ty_err
) env)
3725 (fun lower_bound
(env, prop1
) ->
3728 ~
subtype_env:(make_subtype_env ~coerce
on_error)
3733 (env, TL.conj prop1 prop2
))
3741 (* Add a new lower bound ty on var. Apply transitivity of subtyping
3742 * (so if var <: ty1,...,tyn then assert ty <: tyi for each tyi), using
3743 * simplify_subtype to produce a subtype proposition.
3745 and add_tyvar_lower_bound_and_close
3750 (on_error : Typing_error.Reasons_callback.t
option) =
3751 let lower_bounds_before = Env.get_tyvar_lower_bounds
env var
in
3753 Env.add_tyvar_lower_bound_and_update_variances
3754 ~union
:(try_union_i
env)
3759 let lower_bounds_after = Env.get_tyvar_lower_bounds
env var
in
3760 let added_lower_bounds = ITySet.diff
lower_bounds_after lower_bounds_before in
3761 let upper_bounds = Env.get_tyvar_upper_bounds
env var
in
3764 (fun lower_bound
(env, prop) ->
3765 let (env, ty_err_opt) =
3766 Typing_subtype_tconst.make_all_type_consts_equal
3771 ~as_tyvar_with_cnstr
:false
3775 ~
default:(env, prop)
3776 ~f
:(fun err -> invalid ~
fail:(Some
err) env)
3780 (fun upper_bound
(env, prop1
) ->
3783 ~
subtype_env:(make_subtype_env ~coerce
on_error)
3788 (env, TL.conj prop1 prop2
))
3796 (** [simplify_subtype_arraykey_union env ty_sub tyl_super] implements a special purpose typing
3797 rule for t <: arraykey | tvar by checking t & not arraykey <: tvar. It also works for
3798 not arraykey | tvar. By only applying if B is a type variable, we avoid oscillating
3799 forever between this rule and the generic one that moves from t1 & arraykey <: t2.
3800 to t1 <: t2 | not arraykey. This is similar to our treatment of A <: ?B iff
3801 A & nonnull <: B. This returns a subtyp_prop if the pattern this rule looks for matched,
3802 and returns None if it did not, so that this rule does not apply. ) *)
3803 and simplify_subtype_arraykey_union ~
this_ty ~
subtype_env env ty_sub tyl_super
=
3804 match tyl_super
with
3805 | [ty_super1
; ty_super2
] ->
3806 let (env, ty_super1
) = Env.expand_type
env ty_super1
in
3807 let (env, ty_super2
) = Env.expand_type
env ty_super2
in
3808 (match (deref ty_super1
, deref ty_super2
) with
3809 | ( ((_
, Tvar _
) as tvar_ty
),
3810 ((_
, (Tprim
Aast.Tarraykey
| Tneg
(Neg_prim
Aast.Tarraykey
))) as ak_ty
)
3812 | ( ((_
, (Tprim
Aast.Tarraykey
| Tneg
(Neg_prim
Aast.Tarraykey
))) as ak_ty
),
3813 ((_
, Tvar _
) as tvar_ty
) ) ->
3817 (get_reason
(mk ak_ty
))
3818 ~approx
:Inter.Utils.ApproxDown
3821 let (env, inter_ty
) =
3822 Inter.intersect
env ~
r:(get_reason
ty_sub) neg_ty ty_sub
3829 (LoclType
(mk tvar_ty
))
3836 (* Traverse a list of disjuncts and remove obviously redundant ones.
3837 t1 <: #1 is considered redundant if t2 <: #1 is also a disjunct and t2 <: t1.
3839 #1 <: t1 is considered redundant if #1 <: t2 is also a disjunct and t1 <: t2.
3840 It does not preserve the ordering.
3842 and simplify_disj
env disj
=
3843 let rec add_new_bound ~is_lower ~coerce ~constr
ty bounds
=
3845 | [] -> [(is_lower
, ty, constr
)]
3846 | ((is_lower'
, bound_ty
, _
) as b
) :: bounds
->
3848 is_lower
&& is_lower'
&& is_sub_type_for_union_i ~coerce
env bound_ty
ty
3852 is_lower
&& is_lower'
&& is_sub_type_for_union_i ~coerce
env ty bound_ty
3854 add_new_bound ~is_lower ~coerce ~constr
ty bounds
3858 && is_sub_type_for_union_i ~coerce
env ty bound_ty
3864 && is_sub_type_for_union_i ~coerce
env bound_ty
ty
3866 add_new_bound ~is_lower ~coerce ~constr
ty bounds
3868 b
:: add_new_bound ~is_lower ~coerce ~constr
ty bounds
3870 (* Map a type variable to a list of lower and upper bound types. For any two types
3871 t1 and t2 both lower or upper in the list, it is not the case that t1 <: t2 or t2 <: t1.
3873 let bound_map = ref IMap.empty in
3874 let process_bound ~is_lower ~coerce ~constr
ty var
=
3877 | LoclType
ty when not is_lower
->
3878 LoclType
(transform_dynamic_upper_bound ~coerce
env ty)
3881 match IMap.find_opt var
!bound_map with
3882 | None
-> bound_map := IMap.add var
[(is_lower
, ty, constr
)] !bound_map
3884 let new_bounds = add_new_bound ~is_lower ~coerce ~constr
ty bounds
in
3885 bound_map := IMap.add var
new_bounds !bound_map
3887 let rec fill_bound_map disj
=
3892 | TL.Conj _
-> d
:: fill_bound_map disj
3893 | TL.Disj
(_
, props
) -> fill_bound_map (props
@ disj
)
3894 | TL.IsSubtype
(coerce
, ty_sub, ty_super) ->
3895 (match get_tyvar_opt ty_super with
3897 process_bound ~is_lower
:true ~coerce ~constr
:d
ty_sub var_super
;
3900 (match get_tyvar_opt ty_sub with
3902 process_bound ~is_lower
:false ~coerce ~constr
:d
ty_super var_sub
;
3904 | None
-> d
:: fill_bound_map disj
)))
3906 (* Get the constraints from the table that were not removed, and add them to
3907 the remaining constraints that were not of the form we were looking for. *)
3908 let rec rebuild_disj remaining to_process
=
3909 match to_process
with
3911 | (_
, bounds
) :: to_process
->
3912 List.map ~f
:(fun (_
, _
, c
) -> c
) bounds
3913 @ rebuild_disj remaining to_process
3915 let remaining = fill_bound_map disj
in
3916 let bounds = IMap.elements
!bound_map in
3917 rebuild_disj remaining bounds
3926 (on_error : Typing_error.Reasons_callback.t
option) =
3927 let props_to_env = props_to_env ty_sub ty_super in
3929 | [] -> (env, List.rev ty_errs
, List.rev remain
)
3933 props_to_env env ty_errs remain
(props'
@ props
) on_error
3934 | TL.Disj
(ty_err_opt, disj_props
) ->
3935 (* For now, just find the first prop in the disjunction that works *)
3936 let rec try_disj disj_props
=
3937 match disj_props
with
3939 (* For now let it fail later when calling
3940 process_simplify_subtype_result on the remaining constraints. *)
3941 props_to_env env (ty_err_opt :: ty_errs
) remain props
on_error
3942 | prop :: disj_props'
->
3943 let (env'
, ty_errs'
, other
) =
3944 props_to_env env [] remain
[prop] on_error
3946 if List.is_empty ty_errs'
|| List.for_all ty_errs' ~f
:Option.is_none
3948 props_to_env env' ty_errs
(remain
@ other
) props
on_error
3950 try_disj disj_props'
3953 let rec log_non_singleton_disj msg props
=
3956 | [TL.Disj
(_
, props
)] -> log_non_singleton_disj msg props
3961 (Reason.to_pos
(get_reason_i
ty_sub))
3962 ("non-singleton disjunction "
3965 ^
Typing_print.full_i
env ty_sub
3967 ^
Typing_print.full_i
env ty_super)
3971 let simplified_disj_props = simplify_disj
env disj_props
in
3972 log_non_singleton_disj "before simplification" disj_props
;
3973 log_non_singleton_disj "after simplification" simplified_disj_props;
3974 try_disj simplified_disj_props
3975 | TL.IsSubtype
(coerce
, ty_sub, ty_super) ->
3977 match (get_tyvar_opt ty_sub, get_tyvar_opt ty_super) with
3978 | (Some var_sub
, Some var_super
) ->
3980 add_tyvar_upper_bound_and_close
3988 add_tyvar_lower_bound_and_close
3995 props_to_env env ty_errs remain
(prop1
:: prop2
:: props
) on_error
3998 add_tyvar_upper_bound_and_close
4005 props_to_env env ty_errs remain
(prop :: props
) on_error
4008 add_tyvar_lower_bound_and_close
4015 props_to_env env ty_errs remain
(prop :: props
) on_error
4016 | _
-> props_to_env env ty_errs
(prop :: remain
) props
on_error
4019 (* Given a subtype proposition, resolve conjunctions of subtype assertions
4020 * of the form #v <: t or t <: #v by adding bounds to #v in env. Close env
4021 * wrt transitivity i.e. if t <: #v and #v <: u then resolve t <: u which
4022 * may in turn produce more bounds in env.
4023 * For disjunctions, arbitrarily pick the first disjunct that is not
4024 * unsatisfiable. If any unsatisfiable disjunct remains, return it.
4026 and prop_to_env
ty_sub ty_super env prop on_error =
4027 let (env, ty_errs
, props'
) =
4028 props_to_env ty_sub ty_super env [] [] [prop] on_error
4030 let ty_err_opt = Typing_error.union_opt
@@ List.filter_map ~f
:Fn.id ty_errs
in
4031 let env = Env.add_subtype_prop
env (TL.conj_list props'
) in
4036 ~
(subtype_env : subtype_env)
4037 ~
(this_ty : locl_ty
option)
4038 (ty_sub : internal_type
)
4039 (ty_super : internal_type
) : env * Typing_error.t
option =
4046 match subtype_env.coerce
with
4047 | Some
TL.CoerceToDynamic
-> " (dynamic aware)"
4048 | Some
TL.CoerceFromDynamic
-> " (treat dynamic as bottom)"
4054 simplify_subtype_i ~
subtype_env ~
this_ty ty_sub ty_super env
4056 if not
(TL.is_valid
prop) then
4059 (Reason.to_pos
(reason
ty_sub))
4063 prop_to_env
ty_sub ty_super env prop subtype_env.on_error
4065 and is_sub_type_alt_i ~require_completeness ~no_top_bottom ~coerce
env ty1 ty2
=
4068 | LoclType ty1
-> Some ty1
4069 | ConstraintType _
-> None
4074 (make_subtype_env ~require_completeness ~no_top_bottom ~coerce None
)
4076 (* It is weird that this can cause errors, but I am wary to discard them.
4077 * Using the generic unify_error to maintain current behavior. *)
4082 if TL.is_valid
prop then
4084 else if TL.is_unsat
prop then
4089 and is_sub_type_for_union_i
env ?
(coerce
= None
) ty1 ty2
=
4090 let ( = ) = Option.equal
Bool.equal
in
4092 ~require_completeness
:false
4100 and is_sub_type_ignore_generic_params_i
env ty1 ty2
=
4101 let ( = ) = Option.equal
Bool.equal
in
4103 (* TODO(T121047839): Should this set a dedicated ignore_generic_param flag instead? *)
4104 ~require_completeness
:true
4112 (* Attempt to compute the intersection of a type with an existing list intersection.
4113 * If try_intersect env t [t1;...;tn] = [u1; ...; um]
4114 * then u1&...&um must be the greatest lower bound of t and t1&...&tn wrt subtyping.
4116 * try_intersect nonnull [?C] = [C]
4117 * try_intersect t1 [t2] = [t1] if t1 <: t2
4118 * Note: it's acceptable to return [t;t1;...;tn] but the intention is that
4119 * we simplify (as above) wherever practical.
4120 * It can be assumed that the original list contains no redundancy.
4122 and try_intersect_i ?
(ignore_tyvars
= false) env ty tyl
=
4126 let (env, ty) = Env.expand_internal_type
env ty in
4127 let (env, ty'
) = Env.expand_internal_type
env ty'
in
4128 let default env = ty'
:: try_intersect_i
env ~ignore_tyvars
ty tyl'
in
4129 (* Do not attempt to simplify intersection of type variables, as we use
4130 * intersection simplification when transitively closing through type variable
4131 * upper bounds and this would result in a type failing to be added.
4133 if ignore_tyvars
&& (is_tyvar_i
ty || is_tyvar_i
ty'
) then
4135 else if is_sub_type_ignore_generic_params_i
env ty ty'
then
4136 try_intersect_i ~ignore_tyvars
env ty tyl'
4137 else if is_sub_type_ignore_generic_params_i
env ty'
ty then
4140 let nonnull_ty = LoclType
(MakeType.nonnull
(reason
ty)) in
4141 (match (ty, ty'
) with
4143 when is_sub_type_ignore_generic_params_i
env ty'
nonnull_ty ->
4145 match get_node lty
with
4147 try_intersect_i ~ignore_tyvars
env (LoclType t
) (ty'
:: tyl'
)
4151 when is_sub_type_ignore_generic_params_i
env ty nonnull_ty ->
4153 match get_node lty
with
4155 try_intersect_i ~ignore_tyvars
env (LoclType t
) (ty :: tyl'
)
4158 | (_
, _
) -> default env)
4160 and try_intersect ?
(ignore_tyvars
= false) env ty tyl
=
4166 (List.map tyl ~f
:(fun ty -> LoclType
ty)))
4171 "The intersection of two locl type should always be a locl type.")
4173 (* Attempt to compute the union of a type with an existing list union.
4174 * If try_union env t [t1;...;tn] = [u1;...;um]
4175 * then u1|...|um must be the least upper bound of t and t1|...|tn wrt subtyping.
4177 * try_union int [float] = [num]
4178 * try_union t1 [t2] = [t1] if t2 <: t1
4181 * 1. It's acceptable to return [t;t1;...;tn] but the intention is that
4182 * we simplify (as above) wherever practical.
4183 * 2. Do not use Tunion for a syntactic union - the caller can do that.
4184 * 3. It can be assumed that the original list contains no redundancy.
4185 * TODO: there are many more unions to implement yet.
4187 and try_union_i
env ty tyl
=
4191 if is_sub_type_for_union_i
env ty ty'
then
4193 else if is_sub_type_for_union_i
env ty'
ty then
4194 try_union_i
env ty tyl'
4196 let (env, ty) = Env.expand_internal_type
env ty in
4197 let (env, ty'
) = Env.expand_internal_type
env ty'
in
4198 (match (ty, ty'
) with
4199 | (LoclType t1
, LoclType t2
)
4200 when (is_prim
Nast.Tfloat t1
&& is_prim
Nast.Tint t2
)
4201 || (is_prim
Nast.Tint t1
&& is_prim
Nast.Tfloat t2
) ->
4202 let num = LoclType
(MakeType.num (reason
ty)) in
4203 try_union_i
env num tyl'
4204 | (_
, _
) -> ty'
:: try_union_i
env ty tyl'
)
4206 and try_union
env ty tyl
=
4208 (try_union_i
env (LoclType
ty) (List.map tyl ~f
:(fun ty -> LoclType
ty)))
4211 | _
-> failwith
"The union of two locl type should always be a locl type.")
4213 (* Determines whether the types are definitely disjoint, or whether they might
4214 overlap (i.e., both contain some particular value). *)
4215 (* One of the main entry points to this module *)
4216 let sub_type_i ~
subtype_env env ty_sub ty_super =
4217 let old_env = env in
4218 match sub_type_inner ~
subtype_env env ~
this_ty:None
ty_sub ty_super with
4219 | (env, None
) -> (Env.log_env_change
"sub_type" old_env env, None
)
4220 | (_
, ty_err_opt) ->
4221 (Env.log_env_change
"sub_type" old_env old_env, ty_err_opt)
4226 ?
(is_coeffect = false)
4228 (ty_super : locl_ty
)
4231 ~
subtype_env:(make_subtype_env ~
is_coeffect ~coerce
on_error)
4236 let is_sub_type_alt ~require_completeness ~no_top_bottom
env ty1 ty2
=
4238 ~require_completeness
4244 let is_sub_type env ty1 ty2
=
4245 let ( = ) = Option.equal
Bool.equal
in
4247 ~require_completeness
:false
4248 ~no_top_bottom
:false
4255 let is_sub_type_for_union env ?
(coerce
= None
) ty1 ty2
=
4256 let ( = ) = Option.equal
Bool.equal
in
4258 ~require_completeness
:false
4266 let is_sub_type_for_coercion env ty1 ty2
=
4267 let ( = ) = Option.equal
Bool.equal
in
4269 ~require_completeness
:false
4270 ~no_top_bottom
:false
4271 ~coerce
:(Some
TL.CoerceFromDynamic
)
4277 let is_sub_type_ignore_generic_params env ty1 ty2
=
4278 let ( = ) = Option.equal
Bool.equal
in
4280 (* TODO(T121047839): Should this set a dedicated ignore_generic_param flag instead? *)
4281 ~require_completeness
:true
4289 let can_sub_type env ty1 ty2
=
4290 let ( <> ) a b
= not
(Option.equal
Bool.equal a b
) in
4292 ~require_completeness
:false
4300 let is_type_disjoint env ty1 ty2
=
4301 (* visited_tyvars record which type variables we've seen, to cut off cycles. *)
4302 let rec is_type_disjoint visited_tyvars
env ty1 ty2
=
4303 let (env, ty1
) = Env.expand_type
env ty1
in
4304 let (env, ty2
) = Env.expand_type
env ty2
in
4305 match (get_node ty1
, get_node ty2
) with
4306 | (_
, (Tany _
| Terr
| Tdynamic
| Taccess _
| Tunapplied_alias _
))
4307 | ((Tany _
| Terr
| Tdynamic
| Taccess _
| Tunapplied_alias _
), _
) ->
4309 | (Tshape _
, Tshape _
) ->
4310 (* This could be more precise, e.g., if we have two closed shapes with different fields.
4311 However, intersection already detects this and simplifies to nothing, so it's not
4312 so important here. *)
4315 (* Treat shapes as dict<arraykey, mixed> because that implementation detail
4316 leaks through when doing is dict<_, _> on them, and they are also
4317 Traversable, KeyedContainer, etc. (along with darrays).
4318 We could translate darray to a more precise dict type with the same
4319 type arguments, but it doesn't matter since disjointness doesn't ever
4321 let r = get_reason ty1
in
4325 MakeType.(dict
r (arraykey
r) (mixed r))
4328 let r = get_reason ty2
in
4333 MakeType.(dict
r (arraykey
r) (mixed r))
4334 | (Ttuple tyl1
, Ttuple tyl2
) ->
4336 List.exists2 ~f
:(is_type_disjoint visited_tyvars
env) tyl1 tyl2
4338 | List.Or_unequal_lengths.Ok res
-> res
4339 | List.Or_unequal_lengths.Unequal_lengths
-> true)
4341 (* Treat tuples as vec<mixed> because that implementation detail
4342 leaks through when doing is vec<_> on them, and they are also
4343 Traversable, Container, etc. along with varrays.
4344 We could translate varray to a more precise vec type with the same
4345 type argument, but it doesn't matter since disjointness doesn't ever
4347 let r = get_reason ty1
in
4348 is_type_disjoint visited_tyvars
env MakeType.(vec
r (mixed r)) ty2
4350 let r = get_reason ty2
in
4351 is_type_disjoint visited_tyvars
env ty1
MakeType.(vec
r (mixed r))
4352 | (Tvec_or_dict
(tyk
, tyv
), _
) ->
4353 let r = get_reason ty1
in
4357 MakeType.(union
r [vec
r tyv
; dict
r tyk tyv
])
4359 | (_
, Tvec_or_dict
(tyk
, tyv
)) ->
4360 let r = get_reason ty2
in
4365 MakeType.(union
r [vec
r tyv
; dict
r tyk tyv
])
4366 | ((Tgeneric _
| Tnewtype _
| Tdependent _
| Tintersection _
), _
) ->
4368 Typing_utils.get_concrete_supertypes ~abstract_enum
:false env ty1
4370 is_intersection_type_disjoint visited_tyvars
env bounds ty2
4371 | (_
, (Tgeneric _
| Tnewtype _
| Tdependent _
| Tintersection _
)) ->
4373 Typing_utils.get_concrete_supertypes ~abstract_enum
:false env ty2
4375 is_intersection_type_disjoint visited_tyvars
env bounds ty1
4376 | (Tvar tv
, _
) -> is_tyvar_disjoint visited_tyvars
env tv ty2
4377 | (_
, Tvar tv
) -> is_tyvar_disjoint visited_tyvars
env tv ty1
4378 | (Tunion tyl
, _
) ->
4379 List.for_all ~f
:(is_type_disjoint visited_tyvars
env ty2
) tyl
4380 | (_
, Tunion tyl
) ->
4381 List.for_all ~f
:(is_type_disjoint visited_tyvars
env ty1
) tyl
4382 | (Toption ty1
, _
) ->
4383 is_type_disjoint visited_tyvars
env ty1 ty2
4384 && is_type_disjoint visited_tyvars
env (MakeType.null
Reason.Rnone
) ty2
4385 | (_
, Toption ty2
) ->
4386 is_type_disjoint visited_tyvars
env ty1 ty2
4387 && is_type_disjoint visited_tyvars
env ty1
(MakeType.null
Reason.Rnone
)
4389 is_sub_type_for_union env ty2
(MakeType.null
Reason.Rnone
)
4391 is_sub_type_for_union env ty1
(MakeType.null
Reason.Rnone
)
4392 | (Tneg
(Neg_prim tp1
), _
) ->
4393 is_sub_type_for_union env ty2
(MakeType.prim_type
Reason.Rnone tp1
)
4394 | (_
, Tneg
(Neg_prim tp2
)) ->
4395 is_sub_type_for_union env ty1
(MakeType.prim_type
Reason.Rnone tp2
)
4396 | (Tneg
(Neg_class
(_
, c1
)), Tclass
((_
, c2
), _
, _tyl
))
4397 | (Tclass
((_
, c2
), _
, _tyl
), Tneg
(Neg_class
(_
, c1
))) ->
4398 (* These are disjoint iff for all objects o, o in c2<_tyl> implies that
4399 o notin (complement (Union tyl'. c1<tyl'>)), which is just that
4400 c2<_tyl> subset Union tyl'. c1<tyl'>. If c2 is a subclass of c1, then
4401 whatever _tyl is, we can chase up the hierarchy to find an instantiation
4402 for tyl'. If c2 is not a subclass of c1, then no matter what the tyl' are
4403 the subset realtionship cannot hold, since either c1 and c2 are disjoint tags,
4404 or c1 is a non-equal subclass of c2, and so objects that are exact c2,
4405 can't inhabit c1. NB, we aren't allowing abstractness of a class to cause
4406 types to be considered disjoint.
4407 e.g., in abstract class C {}; class D extends C {}, we wouldn't consider
4408 neg D and C to be disjoint.
4410 Typing_utils.is_sub_class_refl
env c2 c1
4414 | (Tprim tp1
, Tprim tp2
) -> is_tprim_disjoint tp1 tp2
4415 | (Tclass
((_
, cname
), ex
, _
), Tprim
(Aast.Tarraykey
| Aast.Tstring
))
4416 | (Tprim
(Aast.Tarraykey
| Aast.Tstring
), Tclass
((_
, cname
), ex
, _
))
4417 when String.equal cname
SN.Classes.cStringish
&& is_nonexact ex
->
4419 | (Tprim _
, (Tfun _
| Tclass _
))
4420 | ((Tfun _
| Tclass _
), Tprim _
) ->
4422 | (Tfun _
, Tfun _
) -> false
4423 | (Tfun _
, Tclass _
)
4424 | (Tclass _
, Tfun _
) ->
4426 | (Tclass
((_
, c1
), _
, _
), Tclass
((_
, c2
), _
, _
)) ->
4427 is_class_disjoint env c1 c2
4428 (* incomplete, e.g., is_intersection_type_disjoint (?int & ?float) num *)
4429 and is_intersection_type_disjoint visited_tvyars
env inter_tyl
ty =
4430 List.exists ~f
:(is_type_disjoint visited_tvyars
env ty) inter_tyl
4431 and is_intersection_itype_set_disjoint visited_tvyars
env inter_ty_set
ty =
4432 ITySet.exists
(is_itype_disjoint visited_tvyars
env ty) inter_ty_set
4433 and is_itype_disjoint
4434 visited_tvyars
env (lty1
: locl_ty
) (ity
: internal_type
) =
4436 | LoclType lty2
-> is_type_disjoint visited_tvyars
env lty1 lty2
4437 | ConstraintType _
-> false
4438 and is_tyvar_disjoint visited_tyvars
env (tyvar
: int) ty =
4439 if ISet.mem tyvar visited_tyvars
then
4440 (* There is a cyclic type variable bound, this will lead to a type error *)
4443 let bounds = Env.get_tyvar_upper_bounds
env tyvar
in
4444 is_intersection_itype_set_disjoint
4445 (ISet.add tyvar visited_tyvars
)
4450 is_type_disjoint ISet.empty env ty1 ty2
4452 let decompose_subtype_add_bound
4453 ~coerce
(env : env) (ty_sub : locl_ty
) (ty_super : locl_ty
) : env =
4454 let (env, ty_super) = Env.expand_type
env ty_super in
4455 let (env, ty_sub) = Env.expand_type
env ty_sub in
4456 match (get_node
ty_sub, get_node
ty_super) with
4457 | (_
, Tany _
) -> env
4458 (* name_sub <: ty_super so add an upper bound on name_sub *)
4459 | (Tgeneric
(name_sub
, targs
), _
) when not
(phys_equal
ty_sub ty_super) ->
4460 let ty_super = transform_dynamic_upper_bound ~coerce
env ty_super in
4461 (* TODO(T69551141) handle type arguments. Passing targs to get_lower_bounds,
4462 but the add_upper_bound call must be adapted *)
4466 ~function_name
:"decompose_subtype_add_bound"
4470 let tys = Env.get_upper_bounds
env name_sub targs
in
4471 (* Don't add the same type twice! *)
4472 if Typing_set.mem
ty_super tys then
4475 Env.add_upper_bound ~intersect
:(try_intersect
env) env name_sub
ty_super
4476 (* ty_sub <: name_super so add a lower bound on name_super *)
4477 | (_
, Tgeneric
(name_super
, targs
)) when not
(phys_equal
ty_sub ty_super) ->
4478 (* TODO(T69551141) handle type arguments. Passing targs to get_lower_bounds,
4479 but the add_lower_bound call must be adapted *)
4483 ~function_name
:"decompose_subtype_add_bound"
4487 let tys = Env.get_lower_bounds
env name_super targs
in
4488 (* Don't add the same type twice! *)
4489 if Typing_set.mem
ty_sub tys then
4492 Env.add_lower_bound ~union
:(try_union
env) env name_super
ty_sub
4495 (* Given two types that we know are in a subtype relationship
4496 * ty_sub <: ty_super
4497 * add to env.tpenv any bounds on generic type parameters that must
4498 * hold for ty_sub <: ty_super to be valid.
4500 * For example, suppose we know Cov<T> <: Cov<D> for a covariant class Cov.
4501 * Then it must be the case that T <: D so we add an upper bound D to the
4504 * Although some of this code is similar to that for sub_type_inner, its
4505 * purpose is different. sub_type_inner takes two types t and u and makes
4506 * updates to the substitution of type variables (through unification) to
4509 * decompose_subtype takes two types t and u for which t <: u is *assumed* to
4510 * hold, and makes updates to bounds on generic parameters that *necessarily*
4511 * hold in order for t <: u.
4513 let rec decompose_subtype
4516 (ty_super : locl_ty
)
4517 (on_error : Typing_error.Reasons_callback.t
option) : env =
4521 ~function_name
:"decompose_subtype"
4529 ~require_soundness
:false
4530 ~require_completeness
:true
4537 decompose_subtype_add_prop
env prop
4539 and decompose_subtype_add_prop
env prop =
4542 List.fold_left ~f
:decompose_subtype_add_prop ~init
:env props
4543 | TL.Disj
(_
, []) -> Env.mark_inconsistent
env
4544 | TL.Disj
(_
, [prop'
]) -> decompose_subtype_add_prop
env prop'
4546 let callable_pos = env.genv
.callable_pos in
4549 (Pos_or_decl.of_raw_pos
callable_pos)
4550 "decompose_subtype_add_prop"
4554 | TL.IsSubtype
(coerce
, LoclType ty1
, LoclType ty2
) ->
4555 decompose_subtype_add_bound ~coerce
env ty1 ty2
4558 "Subtyping locl types should yield propositions involving locl types only."
4560 (* Decompose a general constraint *)
4561 and decompose_constraint
4563 (ck
: Ast_defs.constraint_kind
)
4565 (ty_super : locl_ty
)
4567 (* constraints are caught based on reason, not error callback. Using unify_error *)
4569 | Ast_defs.Constraint_as
-> decompose_subtype env ty_sub ty_super on_error
4570 | Ast_defs.Constraint_super
-> decompose_subtype env ty_super ty_sub on_error
4571 | Ast_defs.Constraint_eq
->
4572 let env = decompose_subtype env ty_sub ty_super on_error in
4573 decompose_subtype env ty_super ty_sub on_error
4575 (* Given a constraint ty1 ck ty2 where ck is AS, SUPER or =,
4576 * add bounds to type parameters in the environment that necessarily
4577 * must hold in order for ty1 ck ty2.
4579 * First, we invoke decompose_constraint to add initial bounds to
4580 * the environment. Then we iterate, decomposing constraints that
4581 * arise through transitivity across bounds.
4583 * For example, suppose that env already contains
4585 * for some covariant class C. Now suppose we add the
4586 * constraint "T2 as C<T3>" i.e. we end up with
4587 * C<T1> <: T2 <: C<T3>
4588 * Then by transitivity we know that T1 <: T3 so we add this to the
4591 * We repeat this process until no further bounds are added to the
4592 * environment, or some limit is reached. (It's possible to construct
4593 * types that expand forever under inheritance.)
4595 let constraint_iteration_limit = 20
4599 (ck
: Ast_defs.constraint_kind
)
4601 (ty_super : locl_ty
)
4606 ~function_name
:"add_constraint"
4610 let oldsize = Env.get_tpenv_size
env in
4611 let env = decompose_constraint
env ck
ty_sub ty_super on_error in
4612 let ( = ) = Int.equal
in
4613 if Env.get_tpenv_size
env = oldsize then
4616 let rec iter n
env =
4617 if n
> constraint_iteration_limit then
4620 let oldsize = Env.get_tpenv_size
env in
4623 (Env.get_generic_parameters
env)
4627 (* TODO(T70068435) always using [] as args for now *)
4628 (Typing_set.elements
(Env.get_lower_bounds
env x
[]))
4630 ~f
:(fun env ty_sub'
->
4632 (* TODO(T70068435) always using [] as args for now *)
4633 (Typing_set.elements
(Env.get_upper_bounds
env x
[]))
4635 ~f
:(fun env ty_super'
->
4636 decompose_subtype env ty_sub'
ty_super'
on_error)))
4638 if Int.equal
(Env.get_tpenv_size
env) oldsize then
4645 let add_constraints p env constraints
=
4646 let add_constraint env (ty1
, ck
, ty2
) =
4647 add_constraint env ck ty1 ty2
4648 @@ Some
(Typing_error.Reasons_callback.unify_error_at
p)
4650 List.fold_left constraints ~f
:add_constraint ~init
:env
4652 let sub_type_with_dynamic_as_bottom env ty_sub ty_super on_error =
4656 ~function_name
:"coercion"
4660 let old_env = env in
4664 (make_subtype_env ~coerce
:(Some
TL.CoerceFromDynamic
) on_error)
4671 prop_to_env
(LoclType
ty_sub) (LoclType
ty_super) env prop on_error
4673 ( (if Option.is_some ty_err
then
4679 let simplify_subtype_i ?
(is_coeffect = false) env ty_sub ty_super ~
on_error =
4681 ~
subtype_env:(make_subtype_env ~
is_coeffect ~no_top_bottom
:true on_error)
4686 (*****************************************************************************)
4688 (*****************************************************************************)
4690 let sub_type_i env ?
(is_coeffect = false) ty1 ty2
on_error =
4692 ~
subtype_env:(make_subtype_env ~
is_coeffect ~coerce
:None
on_error)
4698 ~
(check_return
: bool)
4701 (ft_sub
: locl_fun_type
)
4702 (r_super : Reason.t
)
4703 (ft_super
: locl_fun_type
)
4705 (* This is used for checking subtyping of function types for method override
4706 * (see Typing_subtype_method) so types are fully-explicit and therefore we
4707 * permit subtyping to dynamic when --enable-sound-dynamic-type is true
4709 let old_env = env in
4711 simplify_subtype_funs
4712 ~
subtype_env:(make_subtype_env ~coerce
:(Some
TL.CoerceToDynamic
) on_error)
4722 (LoclType
(mk
(r_sub, Tfun ft_sub
)))
4723 (LoclType
(mk
(r_super, Tfun ft_super
)))
4728 ( (if Option.is_some ty_err
then
4734 let sub_type_or_fail env ty1 ty2
err_opt =
4735 sub_type env ty1 ty2
4736 @@ Option.map ~f
:Typing_error.Reasons_callback.always
err_opt
4738 let is_sub_type_for_union = is_sub_type_for_union ~coerce
:None
4740 let is_sub_type_for_union_i = is_sub_type_for_union_i ~coerce
:None
4742 let set_fun_refs () =
4743 Typing_utils.sub_type_ref
:= sub_type;
4744 Typing_utils.sub_type_i_ref
:= sub_type_i;
4745 Typing_utils.sub_type_with_dynamic_as_bottom_ref
:=
4746 sub_type_with_dynamic_as_bottom;
4747 Typing_utils.add_constraint_ref
:= add_constraint;
4748 Typing_utils.is_sub_type_ref
:= is_sub_type;
4749 Typing_utils.is_sub_type_for_coercion_ref
:= is_sub_type_for_coercion;
4750 Typing_utils.is_sub_type_for_union_ref
:= is_sub_type_for_union;
4751 Typing_utils.is_sub_type_for_union_i_ref
:= is_sub_type_for_union_i;
4752 Typing_utils.is_sub_type_ignore_generic_params_ref
:=
4753 is_sub_type_ignore_generic_params;
4754 Typing_utils.is_type_disjoint_ref
:= is_type_disjoint
4756 let () = set_fun_refs ()