Push supportdyn into shapes during subtyping
[hiphop-php.git] / hphp / hack / src / typing / typing_subtype.ml
blobd9aaf110a90d4e212eaf95b8c035955b756b2f34
1 (*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
10 open Hh_prelude
11 open Common
12 open Utils
13 open Typing_defs
14 open Typing_env_types
15 open Typing_logic_helpers
16 module Reason = Typing_reason
17 module Env = Typing_env
18 module Inter = Typing_intersection
19 module TUtils = Typing_utils
20 module SN = Naming_special_names
21 module Phase = Typing_phase
22 module TL = Typing_logic
23 module Cls = Decl_provider.Class
24 module ITySet = Internal_type_set
25 module MakeType = Typing_make_type
26 module Nast = Aast
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
36 * T <: Contra<T> =>
37 * Contra<Contra<T>> <: Contra<T> =>
38 * 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
46 * T <: Contra<T> =>
47 * C <: Contra<T> =>
48 * Contra<B> <: Contra<T> =>
49 * T <: B => // DO NOT REJECT here just because we've visited T before!
50 * C <: B => done.
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
70 None
71 else
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
82 None
83 else
84 Some (SMap.add name (ITySet.add ty lower, upper) v)
85 end
87 let is_err ty =
88 match get_node ty with
89 | Terr -> true
90 | _ -> false
92 type subtype_env = {
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 *)
103 no_top_bottom: bool;
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. *)
113 is_coeffect: bool;
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 =
121 match se.coerce with
122 | Some TL.CoerceFromDynamic -> true
123 | _ -> false
125 let coercing_to_dynamic se =
126 match se.coerce with
127 | Some TL.CoerceToDynamic -> true
128 | _ -> false
130 let make_subtype_env
131 ?(require_soundness = true)
132 ?(require_completeness = false)
133 ?(no_top_bottom = false)
134 ?(coerce = None)
135 ?(is_coeffect = false)
136 on_error =
138 require_soundness;
139 require_completeness;
140 visited = VisitedGoals.empty;
141 no_top_bottom;
142 coerce;
143 is_coeffect;
144 on_error;
145 tparam_constraints = [];
148 let possibly_add_violated_constraint subtype_env ~r_sub ~r_super =
150 subtype_env with
151 tparam_constraints =
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
169 is a type error. *)
170 let detect_attempting_dynamic_coercion_reason r ty =
171 match r with
172 | Reason.Rdynamic_coercion r ->
173 (match ty with
174 | LoclType lty ->
175 (match get_node lty with
176 | Tunion [t1; t2] ->
177 (match (get_node t1, get_node t2) with
178 | (Tdynamic, _) -> (r, LoclType t2)
179 | (_, Tdynamic) -> (r, LoclType t1)
180 | _ -> (r, ty))
181 | _ -> (r, ty))
182 | _ -> (r, ty))
183 | _ -> (r, ty)
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
192 * unification.
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
199 * a subtype holds)
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)
207 * Special cases:
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 =
215 Typing_log.(
216 log_with_level env "sub" ~level (fun () ->
217 let types =
218 [Log_type_i ("ty_sub", ty_sub); Log_type_i ("ty_super", ty_super)]
220 let types =
221 Option.value_map this_ty ~default:types ~f:(fun ty ->
222 Log_type ("this_ty", ty) :: types)
225 level >= 3
226 || not
227 (Typing_utils.is_capability_i ty_sub
228 || Typing_utils.is_capability_i ty_super)
229 then
230 log_types
231 (Reason.to_pos (reason ty_sub))
233 [Log_head (function_name, types)]
234 else
235 ()))
237 let log_subtype ~this_ty ~function_name env ty_sub ty_super =
238 log_subtype_i
239 ~this_ty
240 ~function_name
242 (LoclType ty_sub)
243 (LoclType ty_super)
245 let is_final_and_invariant env id =
246 let class_def = Env.get_class env id in
247 match class_def with
248 | Some class_ty -> TUtils.class_is_final_and_invariant class_ty
249 | None -> false
251 let is_tprim_disjoint tp1 tp2 =
252 let one_side tp1 tp2 =
253 Aast_defs.(
254 match (tp1, tp2) with
255 | (Tnum, Tint)
256 | (Tnum, Tfloat)
257 | (Tarraykey, Tint)
258 | (Tarraykey, Tstring)
259 | (Tarraykey, Tnum) ->
260 false
261 | ( _,
262 ( Tnum | Tint | Tvoid | Tbool | Tarraykey | Tfloat | Tstring | Tnull
263 | Tresource | Tnoreturn ) ) ->
264 true)
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 =
272 Ast_defs.(
273 match Cls.kind c_def with
274 | Cinterface
275 | Ctrait ->
276 true
277 | Cclass _
278 | Cenum_class _
279 | Cenum ->
280 false)
282 if String.equal c1 c2 then
283 false
284 else
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)
293 else
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)
302 | _ ->
303 (* This is a decl error that should have already been caught *)
304 false
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
308 negations). *)
309 let negate_ak_null_type env r ty =
310 let (env, ty) = Env.expand_type env ty in
311 let neg_ty =
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)
318 | _ -> None
320 (env, neg_ty)
322 let find_type_with_exact_negation env tyl =
323 let rec find env tyl acc_tyl =
324 match tyl with
325 | [] -> (env, None, acc_tyl)
326 | ty :: tyl' ->
327 let (env, neg_ty) = negate_ak_null_type env (get_reason ty) ty in
328 (match neg_ty with
329 | None -> find env tyl' (ty :: acc_tyl)
330 | Some neg_ty -> (env, Some neg_ty, tyl' @ acc_tyl))
332 find env 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
342 describe_ty_default
343 else
344 fun env -> function
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
352 match ty with
353 | LoclType ty ->
354 let (env, ty) = Env.expand_type env ty in
355 (match get_node ty with
356 | Tvar v ->
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. *)
359 let upper_bounds =
360 List.filter upper_bounds ~f:(fun t -> not (is_tyvar_i t))
362 (match upper_bounds with
363 | [] -> "some type not known yet"
364 | tyl ->
365 let (locl_tyl, cstr_tyl) = List.partition_tf tyl ~f:is_locl_type in
366 let sep =
367 match (locl_tyl, cstr_tyl) with
368 | (_ :: _, _ :: _) -> " and "
369 | _ -> ""
371 let locl_descr =
372 match locl_tyl with
373 | [] -> ""
374 | tyl ->
375 "of type "
376 ^ (String.concat ~sep:" & " (List.map tyl ~f:print)
377 |> Markdown_lite.md_codify)
379 let cstr_descr =
380 String.concat
381 ~sep:" and "
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) ->
391 let {
392 hm_name = (_, name);
393 hm_type = _;
394 hm_class_id = _;
395 hm_explicit_targs = targs;
399 (match targs with
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)) ->
403 Printf.sprintf
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)) ->
414 Printf.sprintf
415 "%s or %s"
416 (describe_ty_super env (LoclType lty))
417 (describe_ty_super env (ConstraintType cty))
418 | (_, TCintersection (lty, cty)) ->
419 Printf.sprintf
420 "%s and %s"
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
426 let ty_constraints =
427 match ety with
428 | Typing_defs.LoclType ty -> Typing_print.constraints_for_type env ty
429 | Typing_defs.ConstraintType _ -> ""
432 let ( = ) = String.equal in
433 let ty_constraints =
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
439 else
440 " " ^ ty_constraints
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)
454 | Tgeneric _
455 | Tdynamic
456 | Terr
457 | Tany _
458 | Toption _
459 | Tvar _
460 | Taccess _
461 | Tunapplied_alias _
462 | Tneg _
463 | Tintersection _ ->
464 false
465 | Tunion tys -> List.for_all tys ~f:null_not_subtype
466 | Tclass _
467 | Tprim _
468 | Tnonnull
469 | Tfun _
470 | Ttuple _
471 | Tshape _
472 | Tvec_or_dict _ ->
473 true
474 | Tdependent (_, bound)
475 | Tnewtype (_, _, bound) ->
476 null_not_subtype bound
478 let get_tyvar_opt t =
479 match t with
480 | LoclType lt ->
481 begin
482 match get_node lt with
483 | Tvar var -> Some var
484 | _ -> None
486 | _ -> None
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 =
499 if super_like then
500 Typing_utils.make_like env ty
501 else
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
513 else
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
519 | _ -> ty
521 let mk_issubtype_prop ~coerce env ty1 ty2 =
522 match ty2 with
523 | LoclType ty2 ->
524 let (coerce, 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
532 ( None,
533 MakeType.union
535 [non_dyn_ty; MakeType.supportdyn r (MakeType.mixed r)] )
536 | _ -> (coerce, ty2)
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 ->
544 (true, tyarg)
545 | _ -> (false, ty)
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
558 * propagate it.
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)
566 ty_sub
567 ty_super =
568 simplify_subtype_i
569 ~subtype_env
570 ~this_ty
571 ~super_like
572 ~sub_supportdyn
573 ~super_supportdyn
574 (LoclType ty_sub)
575 (LoclType ty_super)
577 and simplify_dynamic_aware_subtype ~subtype_env =
578 simplify_subtype
579 ~subtype_env:{ subtype_env with coerce = Some TL.CoerceToDynamic }
581 and default_subtype
582 ~subtype_env
583 ~(this_ty : locl_ty option)
584 ?(super_like = false)
585 ~fail
587 ty_sub
588 ty_super =
589 let default env =
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
598 * here
600 match ty_sub with
601 | ConstraintType cty_sub ->
602 begin
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 ->
615 begin
616 match deref lty_sub with
617 | (_, Tunion tyl) ->
619 * t1 | ... | tn <: t
620 * if and only if
621 * t1 <: t /\ ... /\ tn <: t
622 * We want this even if t is a type variable e.g. consider
623 * int | v <: v
625 List.fold_left tyl ~init:(env, TL.valid) ~f:(fun res ty_sub ->
627 &&& simplify_subtype_i
628 ~subtype_env
629 ~super_like
630 (LoclType ty_sub)
631 ty_super)
632 | (_, Terr) ->
633 if subtype_env.no_top_bottom then
634 default env
635 else
636 valid env
637 | (_, Tvar id) ->
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)
653 then
654 valid env
655 else
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 ->
660 valid env
661 | _ -> default env)
662 (* Special case if Tany is in an intersection on the left:
663 * t1 & ... & _ & ... & tn <: u
664 * simplifies to
665 * _ <: u
667 | (r, Tintersection tyl) when List.exists tyl ~f:is_any ->
668 simplify_subtype_i
669 ~this_ty
670 ~subtype_env
671 (LoclType (mk (r, Typing_defs.make_tany ())))
672 ty_super
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
683 | _ ->
684 (* It's sound to reduce t1 & t2 <: t to (t1 <: t) || (t2 <: t), but
685 * not complete.
686 * TODO(T120921930): Don't do this if require_completeness is set.
688 List.fold_left
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
698 default env
699 else
700 (* If we've seen this type parameter before then we must have gone
701 * round a cycle so we fail
703 match
704 VisitedGoals.try_add_visited_generic_sub
705 subtype_env.visited
706 name_sub
707 ty_super
708 with
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
715 let this_ty =
717 DependentKind.is_generic_dep_ty name_sub
718 && Option.is_none this_ty
719 then
720 Some lty_sub
721 else
722 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 =
729 match tyl with
730 | [] ->
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
735 a lower bound.
737 let r =
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
743 | [ty] ->
744 simplify_subtype_i
745 ~subtype_env
746 ~this_ty
747 ~super_like
748 (LoclType ty)
749 ty_super
751 | ty :: tyl ->
753 |> try_bounds tyl
754 ||| simplify_subtype_i
755 ~subtype_env
756 ~this_ty
757 ~super_like
758 (LoclType ty)
759 ty_super
762 |> try_bounds
763 (Typing_set.elements
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)) ->
770 simplify_subtype_i
771 ~subtype_env
772 ~this_ty
773 ~super_like
774 (LoclType ty)
775 ty_super
777 | (_, Tdependent (_, ty)) ->
778 let this_ty = Option.first_some this_ty (Some lty_sub) in
779 simplify_subtype_i
780 ~subtype_env
781 ~this_ty
782 ~super_like
783 (LoclType ty)
784 ty_super
786 | _ -> invalid ~fail env
789 (* We further refine the default subtype case for rules that apply to all
790 * LoclTypes but not to ConstraintTypes
792 match ty_super with
793 | LoclType lty_super ->
794 (match ty_sub with
795 | ConstraintType _ -> default_subtype_inner env ty_sub ty_super
796 | LoclType lty_sub ->
797 begin
798 match deref lty_sub with
799 | (_, Tvar _) ->
800 begin
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)
806 | (Some cd, _) ->
807 ( env,
808 mk_issubtype_prop
809 ~coerce:(Some cd)
811 (LoclType lty_sub)
812 (LoclType lty_super) )
813 | (None, _) -> default_subtype_inner env ty_sub ty_super
815 | (r_sub, Tprim Nast.Tvoid) ->
816 let r =
817 Reason.Rimplicit_upper_bound (Reason.to_pos r_sub, "?nonnull")
819 simplify_subtype
820 ~subtype_env
821 ~this_ty
822 (MakeType.mixed r)
823 lty_super
825 |> if_unsat (invalid ~fail)
826 | (_, Tany _) ->
827 if subtype_env.no_top_bottom then
828 default env
829 else
830 valid env
831 | _ -> default_subtype_inner env ty_sub ty_super
832 end)
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)
846 * C <: J ==> Unsat _
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 =
860 log_subtype_i
861 ~level:2
862 ~this_ty
863 ~function_name:
864 ("simplify_subtype"
865 ^ (match subtype_env.coerce with
866 | None -> ""
867 | Some TL.CoerceToDynamic -> " <:D"
868 | Some TL.CoerceFromDynamic -> " D<:")
870 let flag str = function
871 | true -> str
872 | false -> ""
874 flag " super-like" super_like
875 ^ flag " require_soundness" subtype_env.require_soundness
876 ^ flag " require_completeness" subtype_env.require_completeness)
878 ty_sub
879 ty_super;
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 () ->
884 let subtype_env =
885 possibly_add_violated_constraint
886 subtype_env
887 ~r_sub:(reason ety_sub)
888 ~r_super:(reason ety_super)
890 let fail_with_suffix snd_err_opt =
891 let reasons =
892 lazy
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 )
905 else
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
910 left @ right)
912 let err_opt =
913 let open Typing_error in
914 match subtype_env.tparam_constraints with
915 | [] ->
916 let snd_err1 = Secondary.Subtyping_error reasons in
917 (match snd_err_opt with
918 | Some snd_err2 ->
919 Option.map subtype_env.on_error ~f:(fun on_error ->
920 apply_reasons
921 ~on_error:
922 Reasons_callback.(
923 prepend_on_apply (retain_code on_error) snd_err1)
924 snd_err2)
925 | _ ->
926 Option.map subtype_env.on_error ~f:(fun on_error ->
927 apply_reasons
928 ~on_error:(Reasons_callback.retain_code on_error)
929 snd_err1))
930 | cstrs ->
931 let snd_err1 = Secondary.Violated_constraint { cstrs; reasons } in
932 (match snd_err_opt with
933 | Some snd_err2 ->
934 Option.map subtype_env.on_error ~f:(fun on_error ->
935 apply_reasons
936 ~on_error:(Reasons_callback.prepend_on_apply on_error snd_err1)
937 snd_err2)
938 | None ->
939 Option.map subtype_env.on_error ~f:(fun on_error ->
940 apply_reasons ~on_error snd_err1))
942 err_opt
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 *)
951 let default env =
952 (env, mk_issubtype_prop ~coerce:subtype_env.coerce env ety_sub ety_super)
954 let default_subtype env =
955 default_subtype
956 ~subtype_env
957 ~this_ty
958 ~super_like
959 ~fail
961 ety_sub
962 ety_super
964 match ety_super with
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)
970 begin
971 match deref_constraint_type cty_super with
972 | (_, TCintersection (lty, cty)) ->
973 (match ety_sub with
974 | LoclType t when is_union t -> default_subtype env
975 | ConstraintType t when is_constraint_type_union t ->
976 default_subtype env
977 | _ ->
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
994 ~subtype_env
995 ~this_ty
996 ~nullsafe:r_null
997 ~fail
998 ety_sub
999 (r, has_member_ty)
1001 | _ -> invalid_env env (* Not possible due to guard in parent match *))
1002 | (_, TCunion (lty_super, cty_super)) ->
1003 (match ety_sub with
1004 | ConstraintType cty when is_constraint_type_union cty ->
1005 default_subtype env
1006 | ConstraintType _ ->
1008 |> simplify_subtype_i ~subtype_env ty_sub (LoclType lty_super)
1009 ||| simplify_subtype_i ~subtype_env ty_sub (ConstraintType cty_super)
1010 ||| default_subtype
1011 | LoclType lty ->
1012 (match deref lty with
1013 | (r, Toption ty) ->
1014 let ty_null = MakeType.null r in
1015 if_unsat
1016 invalid_env
1017 (simplify_subtype_i
1018 ~subtype_env
1019 ~this_ty
1020 (LoclType ty_null)
1021 ty_super
1022 env)
1023 &&& simplify_subtype_i ~subtype_env ~this_ty (LoclType ty) ty_super
1024 | (_, (Tintersection _ | Tunion _ | Terr | Tvar _)) ->
1025 default_subtype env
1026 | _ ->
1028 |> simplify_subtype_i ~subtype_env ty_sub (LoclType lty_super)
1029 ||| simplify_subtype_i
1030 ~subtype_env
1031 ty_sub
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
1045 * } *)
1046 let fpos =
1047 match r_super with
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. *)
1055 invalid_env_with
1057 (Option.map subtype_env.on_error ~f:(fun on_error ->
1058 Typing_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) ->
1063 invalid_env_with
1065 (Option.map subtype_env.on_error ~f:(fun on_error ->
1066 Typing_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)
1074 &&& fun env ->
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)
1077 &&& fun env ->
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
1095 let arity_error f =
1096 let (epos, fpos, prefix) =
1097 match r_super with
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)
1102 invalid_env_with
1105 (prefix + len_required)
1106 (prefix + len_ts)
1107 epos
1108 fpos
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 ->
1114 let base_err =
1115 Typing_error.Secondary.Typing_too_few_args
1116 { pos; decl_pos; expected; actual }
1118 Typing_error.(apply_reasons ~on_error base_err)))
1119 else
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
1123 List.fold2_exn
1124 ts_required
1125 d_required
1126 ~init:(env, TL.valid)
1127 ~f:(fun res ty ty_dest ->
1128 res &&& simplify_subtype ~subtype_env ~this_ty ty ty_dest)
1129 &&& fun env ->
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
1134 else
1135 d_optional
1137 List.fold2_exn
1138 ts_optional
1139 d_optional_part
1140 ~init:(env, TL.valid)
1141 ~f:(fun res ty ty_dest ->
1142 res &&& simplify_subtype ~subtype_env ~this_ty ty ty_dest)
1143 &&& fun env ->
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
1149 | (_, None) ->
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 ->
1153 Typing_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)
1163 &&& fun env ->
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)
1166 &&& fun env ->
1167 Option.value_map ~default:(env, TL.valid) d_variadic ~f:(fun vty ->
1168 simplify_subtype ~subtype_env ~this_ty t vty env)
1169 else
1170 env |> destructure_array t
1172 begin
1173 match ety_sub with
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 *)
1189 | (r, Tany _) ->
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? *)
1194 default_subtype env
1195 | _ ->
1196 begin
1197 match d_kind with
1198 | SplatUnpack ->
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 ->
1206 let ty_sub_descr =
1207 lazy
1208 (Typing_print.with_blank_tyvars (fun () ->
1209 Typing_print.full_strip_ns env ty_sub))
1211 default_subtype env
1212 |> if_unsat @@ fun env ->
1213 invalid_env_with
1215 (Option.map
1216 subtype_env.on_error
1218 Typing_error.(
1219 fun 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;
1227 end)
1229 | (r, Tcan_index ci) ->
1230 simplify_subtype_can_index
1231 ~subtype_env
1232 ~this_ty
1233 ~fail
1234 ety_sub
1235 ety_super
1236 (r, ci)
1238 | (r, Tcan_traverse ct) ->
1239 simplify_subtype_can_traverse
1240 ~subtype_env
1241 ~this_ty
1242 ~fail
1243 ety_sub
1244 ety_super
1245 (r, ct)
1247 | (r, Thas_member has_member_ty) ->
1248 simplify_subtype_has_member
1249 ~subtype_env
1250 ~this_ty
1251 ~fail
1252 ety_sub
1253 (r, has_member_ty)
1255 | (r, Thas_type_member (id, ty)) ->
1256 simplify_subtype_has_type_member
1257 ~subtype_env
1258 ~this_ty
1259 ~fail
1260 ety_sub
1261 (r, id, ty)
1264 (* Next deal with all locl types *)
1265 | LoclType ty_super ->
1266 (match deref ty_super with
1267 | (_, Terr) ->
1268 (match ety_sub with
1269 | ConstraintType cty when is_constraint_type_union cty ->
1270 default_subtype env
1271 | ConstraintType _ ->
1272 if subtype_env.no_top_bottom then
1273 default env
1274 else
1275 valid env
1276 | LoclType lty ->
1277 (match deref lty with
1278 | (_, Tunion _) -> default_subtype env
1279 | (_, Terr) -> valid env
1280 | _ ->
1281 if subtype_env.no_top_bottom then
1282 default env
1283 else
1284 valid env))
1285 | (_, Tvar var_super) ->
1286 (match ety_sub with
1287 | ConstraintType cty when is_constraint_type_union cty ->
1288 default_subtype env
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 ->
1294 default_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
1297 * derived rules.
1299 | (r, Toption t) ->
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
1307 | _ ->
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
1313 | _ ->
1314 begin
1315 match subtype_env.coerce with
1316 | Some cd ->
1317 ( env,
1318 mk_issubtype_prop
1319 ~coerce:(Some cd)
1321 (LoclType ty_sub)
1322 (LoclType ty_super) )
1323 | None -> default env
1324 end))
1325 | (_, Tintersection tyl) ->
1326 (match ety_sub with
1327 | ConstraintType cty when is_constraint_type_union cty ->
1328 default_subtype env
1329 | LoclType lty when is_union lty -> default_subtype env
1330 | LoclType lty when is_err lty -> valid env
1331 (* t <: (t1 & ... & tn)
1332 * if and only if
1333 * t <: t1 /\ ... /\ t <: tn
1335 | _ ->
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']) ->
1343 simplify_subtype_i
1344 ~subtype_env
1345 ~this_ty
1346 ~super_like
1347 ty_sub
1348 (LoclType ty_super')
1350 | (r, Tunion (_ :: _ as tyl_super)) ->
1351 let simplify_sub_union env ty_sub tyl_super =
1352 let finish env =
1353 match ty_sub with
1354 | LoclType lty ->
1355 begin
1356 match get_node lty with
1357 | Tnewtype _
1358 | Tdependent _
1359 | Tgeneric _ ->
1360 default_subtype env
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
1368 else
1369 None
1371 match stripped_dynamic with
1372 | Some ty
1373 when is_sub_type_for_union_i
1375 (LoclType ty)
1376 (LoclType (MakeType.supportdyn r (MakeType.mixed r))) ->
1378 |> simplify_subtype_i
1379 ~subtype_env
1380 ~this_ty
1381 ty_sub
1382 (LoclType (MakeType.dynamic r))
1383 ||| simplify_subtype_i
1384 ~subtype_env
1385 ~this_ty
1386 ~super_like:true
1387 ty_sub
1388 (LoclType ty)
1389 ||| finish
1390 | _ ->
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.
1397 let try_push env =
1398 match stripped_dynamic with
1399 | None -> finish env
1400 | Some ty ->
1401 let (env, opt_ty) = Typing_dynamic.try_push_like env ty in
1402 (match opt_ty with
1403 | None -> finish env
1404 | Some ty ->
1405 let simplify_pushed_like env =
1407 |> simplify_dynamic_aware_subtype
1408 ~subtype_env
1409 ~this_ty
1411 (MakeType.dynamic Reason.Rnone)
1412 &&& simplify_subtype_i
1413 ~subtype_env
1414 ~this_ty
1415 ty_sub
1416 (LoclType ty)
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 =
1429 match tys with
1430 | [] -> try_push env
1431 | ty :: tys ->
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
1440 (match ety_sub with
1441 | ConstraintType cty when is_constraint_type_union cty ->
1442 default_subtype env
1443 | ConstraintType _ -> simplify_sub_union env ety_sub tyl_super
1444 | LoclType lty_sub ->
1445 (match
1446 simplify_subtype_arraykey_union
1447 ~this_ty
1448 ~subtype_env
1450 lty_sub
1451 tyl_super
1452 with
1453 | (env, Some props) -> (env, props)
1454 | (env, None) ->
1455 (match deref lty_sub with
1456 | (_, (Tunion _ | Terr | Tvar _)) -> default_subtype env
1457 | (_, Tgeneric _) when subtype_env.require_completeness ->
1458 default_subtype env
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
1471 if_unsat
1472 invalid_env
1473 (simplify_subtype_i
1474 ~subtype_env
1475 ~this_ty
1476 (LoclType ty_null)
1477 ety_super
1478 env)
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 ->
1485 default_subtype env
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
1489 * not complete.
1490 * TODO(T120921930): Don't do this if require_completeness is set.
1492 List.fold_left
1493 tyl_sub
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 :
1505 A & B <: A & B
1506 A & B <: C
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:
1510 A <: B | C
1511 B | C <: B | C
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)
1519 then
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)
1523 else
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
1531 valid env
1532 else (
1533 match ety_sub with
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
1541 simplify_subtype
1542 ~subtype_env
1543 ~super_like
1544 lty_sub
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)
1569 simplify_subtype_i
1570 ~subtype_env
1571 ~super_like
1572 ty_sub'
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'), _) ->
1584 simplify_subtype
1585 ~subtype_env
1586 ~this_ty
1587 ~super_like
1588 ty_sub'
1589 ty_super
1591 (* We do not want to decompose Toption for these cases *)
1592 | ((_, (Tvar _ | Tunion _ | Tintersection _)), _) ->
1593 default_subtype env
1594 | ((_, Tgeneric _), _) when subtype_env.require_completeness ->
1595 (* TODO(T69551141) handle type arguments ? *)
1596 default_subtype env
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
1610 |> simplify_subtype
1611 ~subtype_env
1612 ~this_ty
1613 ~super_like
1614 lty_sub
1615 arg_ty_super
1616 else
1618 |> simplify_subtype
1619 ~subtype_env
1620 ~this_ty
1621 ~super_like
1622 lty_sub
1623 arg_ty_super
1624 ||| default_subtype
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
1628 * of solutions.
1630 | ((_, Tunapplied_alias _), _) ->
1631 Typing_defs.error_Tunapplied_alias_in_illegal_context ()
1632 | ( ( _,
1633 ( Tdynamic | Tprim _ | Tnonnull | Tfun _ | Ttuple _ | Tshape _
1634 | Tclass _ | Tvec_or_dict _ | Tany _ | Terr | Taccess _ ) ),
1635 _ ) ->
1636 simplify_subtype
1637 ~subtype_env
1638 ~this_ty
1639 ~super_like
1640 lty_sub
1641 arg_ty_super
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 _), _) ->
1648 simplify_subtype
1649 ~subtype_env
1650 ~this_ty
1651 ~super_like
1652 lty_sub
1653 arg_ty_super
1654 env)
1656 | (_r_super, Tdependent (d_sup, bound_sup)) ->
1657 let (env, bound_sup) = Env.expand_type env bound_sup in
1658 (match ety_sub with
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) ) ->
1672 let fail =
1673 if String.equal x y then
1674 let p = Reason.to_pos r_sub in
1675 let (pos_super, class_name) = id in
1676 fail_with_suffix
1677 (Some
1678 (Typing_error.Secondary.This_final
1679 { pos_super; class_name; pos_sub = p }))
1680 else
1681 fail
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
1689 else
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 *)
1696 (match ety_sub with
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
1704 valid env
1705 else
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
1712 ~subtype_env
1713 name_sub
1714 variance_reifiedl
1715 tyargs_sub
1716 tyargs_super
1717 ety_sub
1718 ety_super
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 *)
1723 | Tvar _
1724 | Tunion _
1725 | Terr ->
1726 default_subtype env
1727 | _ ->
1728 if subtype_env.require_completeness then
1729 default env
1730 else (
1731 (* If we've seen this type parameter before then we must have gone
1732 * round a cycle so we fail
1734 match
1735 VisitedGoals.try_add_visited_generic_super
1736 subtype_env.visited
1737 ety_sub
1738 name_super
1739 with
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 =
1747 match tyl with
1748 | [] -> default_subtype env
1749 | ty :: tyl ->
1751 |> simplify_subtype ~subtype_env ~this_ty ty_sub ty
1752 ||| try_bounds tyl
1754 (* Turn error into a generic error about the type parameter *)
1756 |> try_bounds
1757 (Typing_set.elements
1758 (Env.get_lower_bounds env name_super tyargs_super))
1759 |> if_unsat invalid_env
1761 | (_, Tnonnull) ->
1762 (match ety_sub with
1763 | ConstraintType cty ->
1764 begin
1765 match deref_constraint_type cty with
1766 | (_, (Thas_member _ | Tdestructure _)) -> valid env
1767 | _ -> default_subtype env
1769 | LoclType lty ->
1770 (match deref lty with
1771 | ( _,
1772 ( Tprim
1773 Nast.(
1774 ( Tint | Tbool | Tfloat | Tstring | Tresource | Tnum
1775 | Tarraykey | Tnoreturn ))
1776 | Tnonnull | Tfun _ | Ttuple _ | Tshape _ | Tclass _
1777 | Tvec_or_dict _ | Taccess _ ) ) ->
1778 valid env
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
1791 (match ety_sub with
1792 | ConstraintType _cty ->
1793 (* TODO *)
1794 default_subtype env
1795 | LoclType lty_sub ->
1796 let dyn = lazy (describe_ty_super ~is_coeffect:false env ety_super) in
1797 let dynamic_part =
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
1802 let postprocess =
1803 if_unsat
1804 (invalid
1805 ~fail:
1806 (Option.map
1807 subtype_env.on_error
1809 Typing_error.(
1810 fun on_error ->
1811 apply_reasons ~on_error
1812 @@ Secondary.Not_sub_dynamic
1813 { pos; ty_name; dynamic_part })))
1815 postprocess
1817 (match deref lty_sub with
1818 | (_, Tany _)
1819 | (_, Terr)
1820 | ( _,
1821 Tprim
1822 ( Tint | Tbool | Tfloat | Tstring | Tnum | Tarraykey | Tvoid
1823 | Tnoreturn | Tresource ) ) ->
1824 valid env
1825 | (_, Tnewtype (name_sub, [_tyarg_sub], _))
1826 when String.equal name_sub SN.Classes.cSupportDyn ->
1827 valid env
1828 | (_, Tnewtype (name_sub, _, _))
1829 when String.equal name_sub SN.Classes.cEnumClassLabel ->
1830 valid env
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
1837 | (_, Tnonnull)
1838 | (_, Tshape (Open_shape, _))
1839 | (_, Tvar _)
1840 | (_, Tunapplied_alias _)
1841 | (_, Tnewtype _)
1842 | (_, Tdependent _)
1843 | (_, Taccess _)
1844 | (_, Tunion _)
1845 | (_, Tintersection _)
1846 | (_, Tgeneric _)
1847 | (_, Tneg _) ->
1848 default_subtype env
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
1853 valid env
1854 else
1855 (* Special case of function type subtype dynamic.
1856 * (function(ty1,...,tyn):ty <: supportdyn<nonnull>)
1857 * iff
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
1864 ~subtype_env
1865 ft_sub.ft_params
1866 ty_dyn_enf
1867 &&& (* Finally do covariant subtryping on return type *)
1868 simplify_subtype ~subtype_env ft_sub.ft_ret.et_type ty_super
1869 | (_, Ttuple tyl) ->
1870 List.fold_left
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)) ->
1876 List.fold_left
1877 ~init:(env, TL.valid)
1878 ~f:(fun res sft ->
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
1884 | None ->
1885 (* This should have been caught already in the naming phase *)
1886 valid env
1887 | Some class_sub ->
1889 Cls.get_support_dynamic_type class_sub || Env.is_enum env class_id
1890 then
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
1899 | ([], _)
1900 | (_, []) ->
1901 valid env
1902 | (tp :: tparams, tyarg :: tyargs) ->
1903 let has_require_dynamic =
1904 Attributes.mem
1905 SN.UserAttributes.uaRequireDynamic
1906 tp.tp_user_attributes
1909 has_require_dynamic
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)
1913 then
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.
1924 let upper_bounds =
1925 List.filter_map tp.tp_constraints ~f:(fun (c, ty) ->
1926 match c with
1927 | Ast_defs.Constraint_as ->
1928 let (_env, ty) =
1929 Phase.localize_no_subst env ~ignore_errors:true ty
1931 Some ty
1932 | _ -> None)
1934 let super =
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
1945 else
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.
1965 let lower_bounds =
1966 List.filter_map tp.tp_constraints ~f:(fun (c, ty) ->
1967 match c with
1968 | Ast_defs.Constraint_super ->
1969 let (_env, ty) =
1970 Phase.localize_no_subst
1972 ~ignore_errors:true
1975 Some ty
1976 | _ -> None)
1978 (match lower_bounds with
1979 | [] -> valid env
1980 | _ ->
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
1986 else (
1987 match Cls.kind class_sub with
1988 | Ast_defs.Cenum_class _ ->
1989 (match Cls.enum_type class_sub with
1990 | Some enum_type ->
1991 let ((env, _ty_err_opt), subtype) =
1992 Typing_utils.localize_no_subst
1993 ~ignore_errors:true
1995 enum_type.te_base
1997 simplify_subtype ~subtype_env subtype ty_super env
1998 | None -> default_subtype env)
1999 | _ -> default_subtype env
2000 ))))
2001 | (_, Tdynamic) ->
2002 (match ety_sub with
2003 | LoclType lty when is_dynamic lty -> valid env
2004 | ConstraintType _
2005 | LoclType _ ->
2006 default_subtype env)
2007 | (_, Tprim prim_ty) ->
2008 (match ety_sub with
2009 | ConstraintType _ -> default_subtype env
2010 | LoclType lty ->
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 ->
2015 valid env
2016 | ((_, Toption arg_ty_sub), Nast.Tnull) ->
2017 simplify_subtype ~subtype_env ~this_ty arg_ty_sub ty_super env
2018 | (_, _) -> default_subtype env))
2019 | (_, Tany _) ->
2020 (match ety_sub with
2021 | ConstraintType cty ->
2022 begin
2023 match deref_constraint_type cty with
2024 | (_, (TCunion _ | TCintersection _)) -> default_subtype env
2025 | _ -> valid 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
2032 | _ -> valid env))
2033 | (r_super, Tfun ft_super) ->
2034 (match ety_sub with
2035 | ConstraintType _ -> default_subtype env
2036 | LoclType lty ->
2037 (match deref lty with
2038 | (r_sub, Tfun ft_sub) ->
2039 simplify_subtype_funs
2040 ~subtype_env
2041 ~check_return:true
2042 ~super_like
2043 r_sub
2044 ft_sub
2045 r_super
2046 ft_super
2048 | _ -> default_subtype env))
2049 | (_, Ttuple tyl_super) ->
2050 (match ety_sub with
2051 | ConstraintType _ -> default_subtype env
2052 (* (t1,...,tn) <: (u1,...,un) iff t1<:u1, ... , tn <: un *)
2053 | LoclType lty ->
2054 (match get_node lty with
2055 | Ttuple tyl_sub
2056 when Int.equal (List.length tyl_super) (List.length tyl_sub) ->
2057 wfold_left2
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)
2061 (env, TL.valid)
2062 tyl_sub
2063 tyl_super
2064 | _ -> default_subtype env))
2065 | (r_super, Tshape (shape_kind_super, fdm_super)) ->
2066 (match ety_sub with
2067 | ConstraintType _ -> default_subtype env
2068 | LoclType lty ->
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
2073 ~subtype_env
2074 ~env
2075 ~this_ty
2076 ~super_like
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 _) ->
2081 (match ety_sub with
2082 | ConstraintType _ -> default_subtype env
2083 | LoclType lty ->
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 ->
2112 (match ety_sub with
2113 | ConstraintType _cty ->
2114 (* TODO *)
2115 default_subtype env
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 ->
2121 |> simplify_subtype
2122 ~subtype_env
2123 ~this_ty
2124 ~super_like
2125 ~super_supportdyn:true
2126 ~sub_supportdyn:true
2127 tyarg_sub
2128 tyarg_super
2129 | (_, (Tgeneric _ | Tvar _)) -> default_subtype env
2130 | _ ->
2131 let ty_dyn = MakeType.dynamic r_supportdyn in
2133 |> simplify_subtype
2134 ~subtype_env
2135 ~this_ty
2136 ~super_like
2137 ~super_supportdyn:true
2138 lty_sub
2139 tyarg_super
2140 &&& simplify_dynamic_aware_subtype
2141 ~subtype_env
2142 ~this_ty
2143 lty_sub
2144 ty_dyn))
2145 | (_, Tnewtype (name_super, tyl_super, _)) ->
2146 (match ety_sub with
2147 | ConstraintType _ -> default_subtype env
2148 | LoclType lty ->
2149 (match deref lty with
2150 | (_, Tclass ((_, name_sub), _, _)) ->
2151 if String.equal name_sub name_super && Env.is_enum env name_super then
2152 valid env
2153 else
2154 default_subtype env
2155 | (_, Tnewtype (name_sub, tyl_sub, _))
2156 when String.equal name_sub name_super ->
2157 if List.is_empty tyl_sub then
2158 valid env
2159 else if Env.is_enum env name_super && Env.is_enum env name_sub then
2160 valid env
2161 else
2162 let td = Env.get_typedef env name_super in
2163 begin
2164 match td with
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
2171 ~subtype_env
2172 ~super_like
2173 name_sub
2174 variance_reifiedl
2175 tyl_sub
2176 tyl_super
2177 ety_sub
2178 ety_super
2180 | None -> invalid_env env
2182 | _ -> default_subtype env))
2183 | (_, Tunapplied_alias n_sup) ->
2184 (match ety_sub with
2185 | ConstraintType _ -> default_subtype env
2186 | LoclType lty ->
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)) ->
2191 (match ety_sub with
2192 | ConstraintType _ -> default_subtype env
2193 | LoclType ty_sub ->
2194 (match deref ty_sub with
2195 | (r_sub, Tneg (Neg_prim tprim_sub)) ->
2196 simplify_subtype
2197 ~subtype_env
2198 ~this_ty
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 *)
2205 invalid_env env
2206 | (_, Tprim tprim_sub) ->
2207 if is_tprim_disjoint tprim_sub tprim_super then
2208 valid env
2209 else
2210 invalid_env env
2211 | (_, Tclass ((_, cname), ex, _))
2212 when String.equal cname SN.Classes.cStringish
2213 && is_nonexact ex
2214 && Aast.(
2215 equal_tprim tprim_super Tstring
2216 || equal_tprim tprim_super Tarraykey) ->
2217 invalid_env env
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))) ->
2222 (match ety_sub with
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
2228 valid env
2229 else
2230 invalid_env env
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 *)
2234 invalid_env env
2235 | (_, Tclass ((_, c_sub), _, _)) ->
2236 if is_class_disjoint env c_sub c_super then
2237 valid env
2238 else
2239 invalid_env env
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
2256 * else ... *)
2257 Class_refinement.fold_type_refs
2258 cr_super
2259 ~init:(valid env)
2260 ~f:(fun type_id (TRexact ty) (env, prop) ->
2261 (env, prop)
2263 let htm_ty =
2264 mk_constraint_type (r_super, Thas_type_member (type_id, ty))
2266 simplify_subtype_i
2267 ~subtype_env
2268 ~this_ty
2269 ~super_like
2270 ety_sub
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
2276 simplify_subtype_i
2277 ~subtype_env
2278 ~this_ty
2279 ~super_like
2280 ety_sub
2281 (LoclType ty_super)
2282 | (_r_super, Tclass (((_, class_name) as x_super), exact_super, tyl_super))
2284 (match ety_sub with
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 ->
2292 valid env
2293 | (_, Tnewtype (cid, _, _))
2294 when String.equal class_name SN.Classes.cHH_BuiltinEnum
2295 && Env.is_enum env cid ->
2296 (match tyl_super with
2297 | [ty_super'] ->
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 ->
2302 valid env
2303 | (_, Tnewtype (enum_name, _, _))
2304 when Env.is_enum env enum_name
2305 && String.equal class_name SN.Classes.cXHPChild ->
2306 valid env
2307 | (_, Tprim Nast.(Tstring | Tarraykey | Tint | Tfloat | Tnum))
2308 when String.equal class_name SN.Classes.cXHPChild
2309 && is_nonexact exact_super ->
2310 valid env
2311 | (_, Tprim Nast.Tstring)
2312 when String.equal class_name SN.Classes.cStringish
2313 && is_nonexact exact_super ->
2314 valid env
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
2318 let exact_match =
2319 match (exact_sub, exact_super) with
2320 | (Nonexact _, Exact) -> false
2321 | (_, _) -> true
2323 if String.equal cid_super cid_sub then
2324 if List.is_empty tyl_sub && List.is_empty tyl_super && exact_match
2325 then
2326 valid env
2327 else
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 *)
2331 let is_final =
2332 match class_def_sub with
2333 | Some tc -> Cls.final tc
2334 | None -> false
2336 if not (exact_match || is_final) then
2337 invalid_env env
2338 else if
2339 (* We handle the case where a generic A<T> is used as A *)
2340 Int.( <> ) (List.length tyl_sub) (List.length tyl_super)
2341 then
2342 let n_sub = List.length tyl_sub in
2343 let n_super = List.length tyl_super in
2344 invalid_env_with
2346 (Option.map
2347 subtype_env.on_error
2349 Typing_error.(
2350 fun on_error ->
2351 apply_reasons ~on_error
2352 @@ Secondary.Type_arity_mismatch
2354 pos = fst x_super;
2355 actual = n_super;
2356 decl_pos = fst x_sub;
2357 expected = n_sub;
2359 else
2360 let variance_reifiedl =
2361 if List.is_empty tyl_sub then
2363 else
2364 match class_def_sub with
2365 | None ->
2366 List.map tyl_sub ~f:(fun _ ->
2367 (Ast_defs.Invariant, Aast.Erased))
2368 | Some class_sub ->
2369 List.map (Cls.tparams class_sub) ~f:(fun t ->
2370 (t.tp_variance, t.tp_reified))
2372 simplify_subtype_variance_for_injective
2373 ~subtype_env
2374 ~super_like
2375 cid_sub
2376 variance_reifiedl
2377 tyl_sub
2378 tyl_super
2380 else if not exact_match then
2381 invalid_env env
2382 else
2383 let class_def_sub = Env.get_class env cid_sub in
2384 (match class_def_sub with
2385 | None ->
2386 (* This should have been caught already in the naming phase *)
2387 valid env
2388 | Some class_sub ->
2389 (* We handle the case where a generic A<T> is used as A *)
2390 let ety_env =
2392 empty_expand_env with
2393 substs =
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
2400 (match up_obj with
2401 | Some up_obj ->
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
2407 simplify_subtype
2408 ~subtype_env
2409 ~this_ty
2410 ~super_like
2411 up_obj
2412 ty_super
2414 | None ->
2416 Ast_defs.is_c_trait (Cls.kind class_sub)
2417 || Ast_defs.is_c_interface (Cls.kind class_sub)
2418 then
2419 let reqs_class =
2420 List.map
2421 (Cls.all_ancestor_req_class_requirements class_sub)
2422 ~f:snd
2424 let rec try_upper_bounds_on_this up_objs env =
2425 match up_objs with
2426 | [] ->
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 *)
2430 invalid_env env
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
2447 |> simplify_subtype
2448 ~subtype_env
2449 ~this_ty
2450 (mk (r_sub, get_node ub_obj_typ))
2451 ty_super
2452 ||| try_upper_bounds_on_this up_objs
2454 try_upper_bounds_on_this
2455 (Cls.upper_bounds_on_this class_sub)
2457 else
2458 invalid_env env))
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)
2481 | (Nonexact _, [])
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 *)
2486 valid env
2487 | (_, _) -> default_subtype env)
2488 | _ -> default_subtype env)))
2490 and simplify_subtype_shape
2491 ~(subtype_env : subtype_env)
2492 ~(env : 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`
2504 EXCEPT
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 =
2511 supportdyn
2512 && not
2513 (is_sub_type_for_union_i
2515 (LoclType ty)
2516 (LoclType (MakeType.supportdyn r (MakeType.mixed r))))
2517 then
2518 MakeType.supportdyn r ty
2519 else
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))
2529 | None ->
2530 begin
2531 match shape_kind with
2532 | Open_shape ->
2533 let printable_name =
2534 TUtils.get_printable_shape_field_name field_name
2536 let mixed_ty =
2537 MakeType.mixed
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) ->
2570 let ty_err_opt =
2571 Option.map
2572 subtype_env.on_error
2574 Typing_error.(
2575 fun 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) ->
2586 let ty_err_opt =
2587 Option.map
2588 subtype_env.on_error
2590 Typing_error.(
2591 fun 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 _) ->
2603 let ty_err_opt =
2604 Option.map
2605 subtype_env.on_error
2607 Typing_error.(
2608 fun 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)
2623 field_name
2624 res =
2625 let proj_sub =
2626 shape_projection
2627 ~supportdyn:supportdyn_sub
2628 field_name
2629 shape_kind_sub
2630 shape_map_sub
2631 r_sub
2633 let proj_super =
2634 shape_projection
2635 ~supportdyn:supportdyn_super
2636 field_name
2637 shape_kind_super
2638 shape_map_super
2639 r_super
2641 simplify_subtype_shape_projection
2642 (r_sub, proj_sub)
2643 (r_super, proj_super)
2644 field_name
2647 match (shape_kind_sub, shape_kind_super) with
2648 (* An open shape cannot subtype a closed shape *)
2649 | (Open_shape, Closed_shape) ->
2650 let fail =
2651 Option.map
2652 subtype_env.on_error
2654 Typing_error.(
2655 fun 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;
2663 invalid ~fail env
2664 (* Otherwise, all projections must subtype *)
2665 | _ ->
2666 TShapeSet.fold
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))
2671 (env, TL.valid)
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 =
2680 log_subtype_i
2681 ~level:2
2682 ~this_ty
2683 ~function_name:"simplify_subtype_can_traverse"
2685 ty_sub
2686 ty_super;
2687 match ty_sub with
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
2692 | Tdynamic ->
2693 simplify_subtype ~subtype_env ~this_ty lty_sub ct.ct_val env
2695 (match ct.ct_key with
2696 | None -> valid
2697 | Some ct_key -> simplify_subtype ~subtype_env ~this_ty lty_sub ct_key)
2698 | Tclass _
2699 | Tvec_or_dict _
2700 | Tany _
2701 | Terr ->
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 =
2708 let htmty =
2709 ConstraintType (mk_constraint_type (r, Thas_type_member (memid, memty)))
2711 log_subtype_i
2712 ~level:2
2713 ~this_ty
2714 ~function_name:"simplify_subtype_has_type_member"
2716 ty_sub
2717 htmty;
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
2722 match ety_sub with
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
2732 ||| fun 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
2740 ucckind
2741 bndtys
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
2759 (x_sub, exact_sub)
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)) ->
2776 default_subtype env
2777 | _ -> invalid ~fail env)
2779 and simplify_subtype_has_member
2780 ~subtype_env
2781 ~this_ty
2782 ~fail
2783 ?(nullsafe : Reason.t option)
2784 ty_sub
2785 (r, has_member_ty)
2786 env =
2787 let using_new_method_call_inference =
2788 TypecheckerOptions.method_call_inference (Env.get_tcopt env)
2790 let {
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;
2796 has_member_ty
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 =
2801 match nullsafe with
2802 | None -> (env, ty)
2803 | Some r_null ->
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)
2812 log_subtype_i
2813 ~level:2
2814 ~this_ty
2815 ~function_name:"simplify_subtype_has_member"
2817 ty_sub
2818 maybe_nullable_ty_super;
2819 let (env, ety_sub) = Env.expand_internal_type env ty_sub in
2820 let default_subtype env =
2821 default_subtype
2822 ~subtype_env
2823 ~this_ty
2824 ~fail
2826 ety_sub
2827 maybe_nullable_ty_super
2829 match ety_sub with
2830 | ConstraintType cty ->
2831 (match deref_constraint_type cty with
2832 | ( _,
2833 Thas_member
2835 hm_name = name_sub;
2836 hm_type = ty_sub;
2837 hm_class_id = cid_sub;
2838 hm_explicit_targs = explicit_targs_sub;
2839 } ) ->
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
2846 && Option.equal
2847 (List.equal targ_equal)
2848 explicit_targs_sub
2849 explicit_targs
2850 then
2851 simplify_subtype ~subtype_env ~this_ty ty_sub member_ty env
2852 else
2853 invalid ~fail 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
2860 valid env
2861 else
2862 invalid
2864 ~fail:
2865 (Some
2866 Typing_error.(
2867 primary
2868 @@ Primary.Null_member
2870 pos = name_pos;
2871 member_name = name_;
2872 reason =
2873 lazy (Reason.to_string "This can be null" r_null);
2874 kind =
2875 (if is_method then
2876 `method_
2877 else
2878 `property);
2879 ctxt = `read;
2881 | (r_option, Toption option_ty) when using_new_method_call_inference ->
2882 if Option.is_some nullsafe then
2883 simplify_subtype_has_member
2884 ~subtype_env
2885 ~this_ty
2886 ~fail
2887 ?nullsafe
2888 (LoclType option_ty)
2889 (r, has_member_ty)
2891 else
2892 let (env, option_ty) = Env.expand_type env option_ty in
2893 (match get_node option_ty with
2894 | Tnonnull ->
2895 invalid
2897 ~fail:
2898 (Some
2899 Typing_error.(
2900 primary
2901 @@ Primary.Top_member
2903 pos = name_pos;
2904 name = name_;
2905 ctxt = `read;
2906 kind =
2907 (if is_method then
2908 `method_
2909 else
2910 `property);
2911 is_nullable = true;
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 [];
2917 | _ ->
2918 invalid
2920 ~fail:
2921 (Some
2922 Typing_error.(
2923 primary
2924 @@ Primary.Null_member
2926 pos = name_pos;
2927 member_name = name_;
2928 reason =
2929 lazy (Reason.to_string "This can be null" r_option);
2930 kind =
2931 (if is_method then
2932 `method_
2933 else
2934 `property);
2935 ctxt = `read;
2936 })))
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 *)
2941 default_subtype env
2942 | (r_inter, Tintersection []) ->
2943 (* Tintersection [] = mixed *)
2944 invalid
2946 ~fail:
2947 (Some
2948 Typing_error.(
2949 primary
2950 @@ Primary.Top_member
2952 pos = name_pos;
2953 name = name_;
2954 is_nullable = true;
2955 kind =
2956 (if is_method then
2957 `method_
2958 else
2959 `property);
2960 ctxt = `read;
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 =
2972 mk_constraint_type
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) =
2979 sub_type_inner
2981 ~subtype_env
2982 ~this_ty
2983 (LoclType ty_sub)
2984 maybe_nullable_fresh_has_member_ty
2986 match ty_err_opt with
2987 | None ->
2988 let (env, _ty_err_opt) =
2989 match get_var fresh_tyvar with
2990 | Some var ->
2991 (* TODO: can this actually generate an error? *)
2992 Typing_solver.solve_to_equal_bound_or_wrt_variance
2994 Reason.Rnone
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
3010 else
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
3017 ~subtype_env
3018 ~this_ty
3019 ~fail
3020 ?nullsafe
3021 (LoclType newtype_ty)
3022 (r, has_member_ty)
3024 (* TODO
3025 | (_, Tdependent _) ->
3026 | (_, Tgeneric _) ->
3028 | _ ->
3029 let explicit_targs =
3030 match explicit_targs with
3031 | None -> []
3032 | Some targs -> targs
3034 let (res, (obj_get_ty, _tal)) =
3035 Typing_object_get.obj_get
3036 ~obj_pos:name_pos
3037 ~is_method
3038 ~inst_meth:false
3039 ~meth_caller:false
3040 ~coerce_from_ty:None
3041 ~nullsafe
3042 ~explicit_targs
3043 ~class_id
3044 ~member_id:name
3045 ~on_error:Typing_error.Callback.unify_error
3047 ty_sub
3049 let prop =
3050 match res with
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 *)
3055 let fail =
3056 Option.map
3057 subtype_env.on_error
3059 Typing_error.(
3060 fun on_error ->
3061 apply_reasons ~on_error @@ Secondary.Of_error ty_err)
3063 invalid env ~fail
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)
3076 (cid : string)
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 =
3080 fun env ->
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.
3085 In the code:
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
3098 we erased generics.
3100 let subtype_env =
3102 (not Aast.(equal_reify_kind reify_kind Erased))
3103 && coercing_from_dynamic subtype_env
3104 then
3105 { subtype_env with coerce = None }
3106 else
3107 subtype_env
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
3115 | ([], _, _)
3116 | (_, [], _)
3117 | (_, _, []) ->
3118 valid env
3119 | ( (variance, reify_kind) :: variance_reifiedl,
3120 child :: childrenl,
3121 super :: superl ) ->
3122 let simplify_subtype = simplify_subtype reify_kind in
3123 begin
3124 match variance with
3125 | Ast_defs.Covariant ->
3126 let super = liken ~super_like env super in
3127 simplify_subtype child super env
3128 | Ast_defs.Contravariant ->
3129 let super =
3131 ( Reason.Rcontravariant_generic (get_reason super, cid),
3132 get_node super )
3134 simplify_subtype super child env
3135 | Ast_defs.Invariant ->
3136 let super' =
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
3145 variance_reifiedl
3146 childrenl
3147 superl
3149 (* Given a type constructor N that may not be injective (e.g., a newtype)
3150 * t1 <:v1> u1 /\ ... /\ tn <:vn> un
3151 * implies
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)
3158 ?super_like
3159 (cid : string)
3160 (variance_reifiedl : (Ast_defs.variance * Aast.reify_kind) list)
3161 (children_tyl : locl_ty list)
3162 (super_tyl : locl_ty list)
3163 ty_sub
3164 ty_super
3165 env =
3166 let ((env, p) as res) =
3167 simplify_subtype_variance_for_injective
3168 ~subtype_env
3169 ?super_like
3171 variance_reifiedl
3172 children_tyl
3173 super_tyl
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)
3183 else
3184 (env, TL.valid)
3185 else
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)
3195 env =
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.
3209 For example, if
3210 ChildClass {
3211 public function a(int $x = 0, string ... $args) // superl = [int], super_var = string
3213 overrides
3214 ParentClass {
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
3225 overrides
3226 ParentClass {
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
3246 &&& begin
3247 if check_params_ifc then
3248 simplify_param_ifc ~subtype_env sub super
3249 else
3250 valid
3252 &&& begin
3253 fun env ->
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)
3268 env =
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
3275 match subl with
3276 | [] -> valid 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
3287 let reasons =
3288 Typing_error.Secondary.Coeffect_subtyping
3290 pos = get_pos got;
3291 cap = Typing_coeffects.pretty env got;
3292 pos_expected = get_pos expected;
3293 cap_expected = Typing_coeffects.pretty env expected;
3296 let on_error =
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
3308 else
3309 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)
3315 env =
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
3322 match superl with
3323 | [] -> valid 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) ->
3335 valid env
3336 | (FPnormal, FPinout) ->
3337 invalid
3338 ~fail:
3339 (Option.map
3340 subtype_env.on_error
3342 Typing_error.(
3343 fun on_error ->
3344 apply_reasons ~on_error
3345 @@ Secondary.Inoutness_mismatch { pos = pos2; decl_pos = pos1 }))
3347 | (FPinout, FPnormal) ->
3348 invalid
3349 ~fail:
3350 (Option.map
3351 subtype_env.on_error
3353 Typing_error.(
3354 fun 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
3363 | (true, false) ->
3364 invalid
3365 ~fail:
3366 (Option.map
3367 subtype_env.on_error
3369 Typing_error.(
3370 fun on_error ->
3371 apply_reasons ~on_error
3372 @@ Secondary.Accept_disposable_invariant
3373 { pos = pos1; decl_pos = pos2 }))
3375 | (false, true) ->
3376 invalid
3377 ~fail:
3378 (Option.map
3379 subtype_env.on_error
3381 Typing_error.(
3382 fun 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
3394 | (true, false) ->
3395 invalid
3396 ~fail:
3397 (Option.map
3398 subtype_env.on_error
3400 Typing_error.(
3401 fun on_error ->
3402 apply_reasons ~on_error
3403 @@ Secondary.Ifc_external_contravariant { pos_super; pos_sub }))
3405 | _ -> valid env
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
3414 invalid
3415 ~fail:
3416 (Option.map
3417 subtype_env.on_error
3419 Typing_error.(
3420 fun on_error ->
3421 apply_reasons ~on_error
3422 @@ Secondary.Readonly_mismatch
3424 pos = pos1;
3425 kind = `param;
3426 reason_sub = lazy [(pos2, "This parameter is mutable")];
3427 reason_super =
3428 lazy [(pos1, "But this parameter is readonly")];
3431 else
3432 valid env
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
3440 | _ -> false
3442 and readonly_subtype (r_sub : bool) (r_super : bool) =
3443 match (r_sub, r_super) with
3444 | (true, false) ->
3445 false (* A readonly value is a supertype of a mutable one *)
3446 | _ -> true
3448 (* Helper function for subtyping on function types: performs all checks that
3449 * don't involve actual types:
3450 * <<__ReturnDisposable>> attribute
3451 * variadic arity
3452 * <<__Policied>> attribute
3453 * Readonlyness
3455 and simplify_subtype_funs_attributes
3456 ~subtype_env
3457 (r_sub : Reason.t)
3458 (ft_sub : locl_fun_type)
3459 (r_super : Reason.t)
3460 (ft_super : locl_fun_type)
3461 env =
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"
3469 (env, TL.valid)
3470 |> check_with
3471 (ifc_policy_matches ft_sub.ft_ifc_decl ft_super.ft_ifc_decl)
3472 (Option.map
3473 subtype_env.on_error
3475 Typing_error.(
3476 fun on_error ->
3477 apply_reasons ~on_error
3478 @@ Secondary.Ifc_policy_mismatch
3480 pos = p_sub;
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;
3485 |> check_with
3486 (readonly_subtype
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))
3490 (Option.map
3491 subtype_env.on_error
3493 Typing_error.(
3494 fun on_error ->
3495 apply_reasons ~on_error
3496 @@ Secondary.Readonly_mismatch
3498 pos = p_sub;
3499 kind = `fn;
3500 reason_sub =
3501 lazy [(p_sub, "This function is not marked readonly")];
3502 reason_super =
3503 lazy [(p_super, "This function is marked readonly")];
3505 |> check_with
3506 (readonly_subtype
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))
3510 (Option.map
3511 subtype_env.on_error
3513 Typing_error.(
3514 fun on_error ->
3515 apply_reasons ~on_error
3516 @@ Secondary.Readonly_mismatch
3518 pos = p_sub;
3519 kind = `fn_return;
3520 reason_sub =
3521 lazy
3522 [(p_sub, "This function returns a readonly value")];
3523 reason_super =
3524 lazy
3526 ( p_super,
3527 "This function does not return a readonly value"
3531 |> check_with
3532 (Bool.equal
3533 (get_ft_return_disposable ft_sub)
3534 (get_ft_return_disposable ft_super))
3535 (Option.map
3536 subtype_env.on_error
3538 Typing_error.(
3539 fun on_error ->
3540 apply_reasons ~on_error
3541 @@ Secondary.Return_disposable_mismatch
3543 pos_super = p_super;
3544 pos_sub = p_sub;
3545 is_marked_return_disposable =
3546 get_ft_return_disposable ft_super;
3548 |> check_with
3549 (arity_min ft_sub <= arity_min ft_super)
3550 (Option.map
3551 subtype_env.on_error
3553 Typing_error.(
3554 fun 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;
3560 pos = p_sub;
3561 decl_pos = p_super;
3563 |> fun res ->
3564 let ft_sub_variadic =
3565 if get_ft_variadic ft_sub then
3566 List.last ft_sub.ft_params
3567 else
3568 None
3570 let ft_super_variadic =
3571 if get_ft_variadic ft_super then
3572 List.last ft_super.ft_params
3573 else
3574 None
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. *)
3584 with_error
3585 (Option.map
3586 subtype_env.on_error
3588 Typing_error.(
3589 fun on_error ->
3590 apply_reasons ~on_error
3591 @@ Secondary.Fun_variadicity_hh_vs_php56
3592 { pos = p_sub; decl_pos = p_super }))
3594 | (None, None) ->
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
3598 with_error
3599 (Option.map
3600 subtype_env.on_error
3602 Typing_error.(
3603 fun on_error ->
3604 apply_reasons ~on_error
3605 @@ Secondary.Fun_too_few_args
3607 pos = p_sub;
3608 decl_pos = p_super;
3609 expected = super_max;
3610 actual = sub_max;
3613 else
3615 | (None, Some _) ->
3616 with_error
3617 (Option.map
3618 subtype_env.on_error
3620 Typing_error.(
3621 fun on_error ->
3622 apply_reasons ~on_error
3623 @@ Secondary.Fun_unexpected_nonvariadic
3624 { pos = p_sub; decl_pos = p_super }))
3626 | (_, _) -> res
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)
3641 (r_sub : Reason.t)
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 *)
3653 begin
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
3663 ~subtype_env
3664 ~check_params_ifc
3665 ft_super.ft_params
3666 ft_sub.ft_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
3678 else
3679 valid
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
3686 ~coerce
3687 (env, prop)
3690 (on_error : Typing_error.Reasons_callback.t option) =
3691 let ty =
3692 match ty with
3693 | LoclType ty -> LoclType (transform_dynamic_upper_bound ~coerce env ty)
3694 | cty -> cty
3696 let upper_bounds_before = Env.get_tyvar_upper_bounds env var in
3697 let env =
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
3707 let (env, prop) =
3708 ITySet.fold
3709 (fun upper_bound (env, prop) ->
3710 let (env, ty_err_opt) =
3711 Typing_subtype_tconst.make_all_type_consts_equal
3714 upper_bound
3715 ~on_error
3716 ~as_tyvar_with_cnstr:true
3718 let (env, prop) =
3719 Option.value_map
3720 ~default:(env, prop)
3721 ~f:(fun ty_err -> invalid ~fail:(Some ty_err) env)
3722 ty_err_opt
3724 ITySet.fold
3725 (fun lower_bound (env, prop1) ->
3726 let (env, prop2) =
3727 simplify_subtype_i
3728 ~subtype_env:(make_subtype_env ~coerce on_error)
3729 lower_bound
3730 upper_bound
3733 (env, TL.conj prop1 prop2))
3734 lower_bounds
3735 (env, prop))
3736 added_upper_bounds
3737 (env, prop)
3739 (env, prop)
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
3746 ~coerce
3747 (env, prop)
3750 (on_error : Typing_error.Reasons_callback.t option) =
3751 let lower_bounds_before = Env.get_tyvar_lower_bounds env var in
3752 let env =
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
3762 let (env, prop) =
3763 ITySet.fold
3764 (fun lower_bound (env, prop) ->
3765 let (env, ty_err_opt) =
3766 Typing_subtype_tconst.make_all_type_consts_equal
3769 lower_bound
3770 ~on_error
3771 ~as_tyvar_with_cnstr:false
3773 let (env, prop) =
3774 Option.value_map
3775 ~default:(env, prop)
3776 ~f:(fun err -> invalid ~fail:(Some err) env)
3777 ty_err_opt
3779 ITySet.fold
3780 (fun upper_bound (env, prop1) ->
3781 let (env, prop2) =
3782 simplify_subtype_i
3783 ~subtype_env:(make_subtype_env ~coerce on_error)
3784 lower_bound
3785 upper_bound
3788 (env, TL.conj prop1 prop2))
3789 upper_bounds
3790 (env, prop))
3791 added_lower_bounds
3792 (env, prop)
3794 (env, prop)
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) ) ->
3814 let (env, neg_ty) =
3815 Inter.negate_type
3817 (get_reason (mk ak_ty))
3818 ~approx:Inter.Utils.ApproxDown
3819 (mk ak_ty)
3821 let (env, inter_ty) =
3822 Inter.intersect env ~r:(get_reason ty_sub) neg_ty ty_sub
3824 let (env, props) =
3825 simplify_subtype_i
3826 ~this_ty
3827 ~subtype_env
3828 (LoclType inter_ty)
3829 (LoclType (mk tvar_ty))
3832 (env, Some props)
3833 | _ -> (env, None))
3834 | _ -> (env, None)
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.
3838 Dually,
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 =
3844 match bounds with
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
3849 then
3850 b :: bounds
3851 else if
3852 is_lower && is_lower' && is_sub_type_for_union_i ~coerce env ty bound_ty
3853 then
3854 add_new_bound ~is_lower ~coerce ~constr ty bounds
3855 else if
3856 (not is_lower)
3857 && (not is_lower')
3858 && is_sub_type_for_union_i ~coerce env ty bound_ty
3859 then
3860 b :: bounds
3861 else if
3862 (not is_lower)
3863 && (not is_lower')
3864 && is_sub_type_for_union_i ~coerce env bound_ty ty
3865 then
3866 add_new_bound ~is_lower ~coerce ~constr ty bounds
3867 else
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 =
3875 let ty =
3876 match ty with
3877 | LoclType ty when not is_lower ->
3878 LoclType (transform_dynamic_upper_bound ~coerce env ty)
3879 | _ -> ty
3881 match IMap.find_opt var !bound_map with
3882 | None -> bound_map := IMap.add var [(is_lower, ty, constr)] !bound_map
3883 | Some bounds ->
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 =
3888 match disj with
3889 | [] -> []
3890 | d :: disj ->
3891 (match d with
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
3896 | Some var_super ->
3897 process_bound ~is_lower:true ~coerce ~constr:d ty_sub var_super;
3898 fill_bound_map disj
3899 | None ->
3900 (match get_tyvar_opt ty_sub with
3901 | Some var_sub ->
3902 process_bound ~is_lower:false ~coerce ~constr:d ty_super var_sub;
3903 fill_bound_map disj
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
3910 | [] -> remaining
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
3919 and props_to_env
3920 ty_sub
3921 ty_super
3923 ty_errs
3924 remain
3925 props
3926 (on_error : Typing_error.Reasons_callback.t option) =
3927 let props_to_env = props_to_env ty_sub ty_super in
3928 match props with
3929 | [] -> (env, List.rev ty_errs, List.rev remain)
3930 | prop :: props ->
3931 (match prop with
3932 | TL.Conj props' ->
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
3938 | [] ->
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
3947 then
3948 props_to_env env' ty_errs (remain @ other) props on_error
3949 else
3950 try_disj disj_props'
3953 let rec log_non_singleton_disj msg props =
3954 match props with
3955 | [] -> ()
3956 | [TL.Disj (_, props)] -> log_non_singleton_disj msg props
3957 | [_] -> ()
3958 | _ ->
3959 Typing_log.log_prop
3961 (Reason.to_pos (get_reason_i ty_sub))
3962 ("non-singleton disjunction "
3963 ^ msg
3964 ^ " of "
3965 ^ Typing_print.full_i env ty_sub
3966 ^ " <: "
3967 ^ Typing_print.full_i env ty_super)
3969 prop
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) ->
3976 begin
3977 match (get_tyvar_opt ty_sub, get_tyvar_opt ty_super) with
3978 | (Some var_sub, Some var_super) ->
3979 let (env, prop1) =
3980 add_tyvar_upper_bound_and_close
3981 ~coerce
3982 (valid env)
3983 var_sub
3984 ty_super
3985 on_error
3987 let (env, prop2) =
3988 add_tyvar_lower_bound_and_close
3989 ~coerce
3990 (valid env)
3991 var_super
3992 ty_sub
3993 on_error
3995 props_to_env env ty_errs remain (prop1 :: prop2 :: props) on_error
3996 | (Some var, _) ->
3997 let (env, prop) =
3998 add_tyvar_upper_bound_and_close
3999 ~coerce
4000 (valid env)
4002 ty_super
4003 on_error
4005 props_to_env env ty_errs remain (prop :: props) on_error
4006 | (_, Some var) ->
4007 let (env, prop) =
4008 add_tyvar_lower_bound_and_close
4009 ~coerce
4010 (valid env)
4012 ty_sub
4013 on_error
4015 props_to_env env ty_errs remain (prop :: props) on_error
4016 | _ -> props_to_env env ty_errs (prop :: remain) props on_error
4017 end)
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
4032 (env, ty_err_opt)
4034 and sub_type_inner
4035 (env : env)
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 =
4040 log_subtype_i
4041 ~level:1
4042 ~this_ty
4043 ~function_name:
4044 ("sub_type_inner"
4046 match subtype_env.coerce with
4047 | Some TL.CoerceToDynamic -> " (dynamic aware)"
4048 | Some TL.CoerceFromDynamic -> " (treat dynamic as bottom)"
4049 | None -> "")
4051 ty_sub
4052 ty_super;
4053 let (env, prop) =
4054 simplify_subtype_i ~subtype_env ~this_ty ty_sub ty_super env
4056 if not (TL.is_valid prop) then
4057 Typing_log.log_prop
4059 (Reason.to_pos (reason ty_sub))
4060 "sub_type_inner"
4062 prop;
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 =
4066 let this_ty =
4067 match ty1 with
4068 | LoclType ty1 -> Some ty1
4069 | ConstraintType _ -> None
4071 let (_env, prop) =
4072 simplify_subtype_i
4073 ~subtype_env:
4074 (make_subtype_env ~require_completeness ~no_top_bottom ~coerce None)
4075 ~this_ty
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
4083 Some true
4084 else if TL.is_unsat prop then
4085 Some false
4086 else
4087 None
4089 and is_sub_type_for_union_i env ?(coerce = None) ty1 ty2 =
4090 let ( = ) = Option.equal Bool.equal in
4091 is_sub_type_alt_i
4092 ~require_completeness:false
4093 ~no_top_bottom:true
4094 ~coerce
4098 = Some true
4100 and is_sub_type_ignore_generic_params_i env ty1 ty2 =
4101 let ( = ) = Option.equal Bool.equal in
4102 is_sub_type_alt_i
4103 (* TODO(T121047839): Should this set a dedicated ignore_generic_param flag instead? *)
4104 ~require_completeness:true
4105 ~no_top_bottom:true
4106 ~coerce:None
4110 = Some 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.
4115 * For example:
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 =
4123 match tyl with
4124 | [] -> [ty]
4125 | 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
4134 default env
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
4139 else
4140 let nonnull_ty = LoclType (MakeType.nonnull (reason ty)) in
4141 (match (ty, ty') with
4142 | (LoclType lty, _)
4143 when is_sub_type_ignore_generic_params_i env ty' nonnull_ty ->
4144 begin
4145 match get_node lty with
4146 | Toption t ->
4147 try_intersect_i ~ignore_tyvars env (LoclType t) (ty' :: tyl')
4148 | _ -> default env
4150 | (_, LoclType lty)
4151 when is_sub_type_ignore_generic_params_i env ty nonnull_ty ->
4152 begin
4153 match get_node lty with
4154 | Toption t ->
4155 try_intersect_i ~ignore_tyvars env (LoclType t) (ty :: tyl')
4156 | _ -> default env
4158 | (_, _) -> default env)
4160 and try_intersect ?(ignore_tyvars = false) env ty tyl =
4161 List.map
4162 (try_intersect_i
4163 ~ignore_tyvars
4165 (LoclType ty)
4166 (List.map tyl ~f:(fun ty -> LoclType ty)))
4167 ~f:(function
4168 | LoclType ty -> ty
4169 | _ ->
4170 failwith
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.
4176 * For example:
4177 * try_union int [float] = [num]
4178 * try_union t1 [t2] = [t1] if t2 <: t1
4180 * Notes:
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 =
4188 match tyl with
4189 | [] -> [ty]
4190 | 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'
4195 else
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 =
4207 List.map
4208 (try_union_i env (LoclType ty) (List.map tyl ~f:(fun ty -> LoclType ty)))
4209 ~f:(function
4210 | LoclType ty -> 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)
4223 let sub_type
4225 ?(coerce = None)
4226 ?(is_coeffect = false)
4227 (ty_sub : locl_ty)
4228 (ty_super : locl_ty)
4229 on_error =
4230 sub_type_i
4231 ~subtype_env:(make_subtype_env ~is_coeffect ~coerce on_error)
4233 (LoclType ty_sub)
4234 (LoclType ty_super)
4236 let is_sub_type_alt ~require_completeness ~no_top_bottom env ty1 ty2 =
4237 is_sub_type_alt_i
4238 ~require_completeness
4239 ~no_top_bottom
4241 (LoclType ty1)
4242 (LoclType ty2)
4244 let is_sub_type env ty1 ty2 =
4245 let ( = ) = Option.equal Bool.equal in
4246 is_sub_type_alt
4247 ~require_completeness:false
4248 ~no_top_bottom:false
4249 ~coerce:None
4253 = Some true
4255 let is_sub_type_for_union env ?(coerce = None) ty1 ty2 =
4256 let ( = ) = Option.equal Bool.equal in
4257 is_sub_type_alt
4258 ~require_completeness:false
4259 ~no_top_bottom:true
4260 ~coerce
4264 = Some true
4266 let is_sub_type_for_coercion env ty1 ty2 =
4267 let ( = ) = Option.equal Bool.equal in
4268 is_sub_type_alt
4269 ~require_completeness:false
4270 ~no_top_bottom:false
4271 ~coerce:(Some TL.CoerceFromDynamic)
4275 = Some true
4277 let is_sub_type_ignore_generic_params env ty1 ty2 =
4278 let ( = ) = Option.equal Bool.equal in
4279 is_sub_type_alt
4280 (* TODO(T121047839): Should this set a dedicated ignore_generic_param flag instead? *)
4281 ~require_completeness:true
4282 ~no_top_bottom:true
4283 ~coerce:None
4287 = Some true
4289 let can_sub_type env ty1 ty2 =
4290 let ( <> ) a b = not (Option.equal Bool.equal a b) in
4291 is_sub_type_alt
4292 ~require_completeness:false
4293 ~no_top_bottom:true
4294 ~coerce:None
4298 <> Some 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 _), _) ->
4308 false
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. *)
4313 false
4314 | (Tshape _, _) ->
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
4320 look at them. *)
4321 let r = get_reason ty1 in
4322 is_type_disjoint
4323 visited_tyvars
4325 MakeType.(dict r (arraykey r) (mixed r))
4327 | (_, Tshape _) ->
4328 let r = get_reason ty2 in
4329 is_type_disjoint
4330 visited_tyvars
4333 MakeType.(dict r (arraykey r) (mixed r))
4334 | (Ttuple tyl1, Ttuple tyl2) ->
4335 (match
4336 List.exists2 ~f:(is_type_disjoint visited_tyvars env) tyl1 tyl2
4337 with
4338 | List.Or_unequal_lengths.Ok res -> res
4339 | List.Or_unequal_lengths.Unequal_lengths -> true)
4340 | (Ttuple _, _) ->
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
4346 look at it. *)
4347 let r = get_reason ty1 in
4348 is_type_disjoint visited_tyvars env MakeType.(vec r (mixed r)) ty2
4349 | (_, Ttuple _) ->
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
4354 is_type_disjoint
4355 visited_tyvars
4357 MakeType.(union r [vec r tyv; dict r tyk tyv])
4359 | (_, Tvec_or_dict (tyk, tyv)) ->
4360 let r = get_reason ty2 in
4361 is_type_disjoint
4362 visited_tyvars
4365 MakeType.(union r [vec r tyv; dict r tyk tyv])
4366 | ((Tgeneric _ | Tnewtype _ | Tdependent _ | Tintersection _), _) ->
4367 let (env, bounds) =
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 _)) ->
4372 let (env, bounds) =
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)
4388 | (Tnonnull, _) ->
4389 is_sub_type_for_union env ty2 (MakeType.null Reason.Rnone)
4390 | (_, Tnonnull) ->
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
4411 | (Tneg _, _)
4412 | (_, Tneg _) ->
4413 false
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 ->
4418 false
4419 | (Tprim _, (Tfun _ | Tclass _))
4420 | ((Tfun _ | Tclass _), Tprim _) ->
4421 true
4422 | (Tfun _, Tfun _) -> false
4423 | (Tfun _, Tclass _)
4424 | (Tclass _, Tfun _) ->
4425 true
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) =
4435 match ity with
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 *)
4441 false
4442 else
4443 let bounds = Env.get_tyvar_upper_bounds env tyvar in
4444 is_intersection_itype_set_disjoint
4445 (ISet.add tyvar visited_tyvars)
4447 bounds
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 *)
4463 log_subtype
4464 ~level:2
4465 ~this_ty:None
4466 ~function_name:"decompose_subtype_add_bound"
4468 ty_sub
4469 ty_super;
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
4474 else
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 *)
4480 log_subtype
4481 ~level:2
4482 ~this_ty:None
4483 ~function_name:"decompose_subtype_add_bound"
4485 ty_sub
4486 ty_super;
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
4491 else
4492 Env.add_lower_bound ~union:(try_union env) env name_super ty_sub
4493 | (_, _) -> env
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
4502 * bounds for T.
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
4507 * make t <: u true.
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
4514 (env : env)
4515 (ty_sub : locl_ty)
4516 (ty_super : locl_ty)
4517 (on_error : Typing_error.Reasons_callback.t option) : env =
4518 log_subtype
4519 ~level:2
4520 ~this_ty:None
4521 ~function_name:"decompose_subtype"
4523 ty_sub
4524 ty_super;
4525 let (env, prop) =
4526 simplify_subtype
4527 ~subtype_env:
4528 (make_subtype_env
4529 ~require_soundness:false
4530 ~require_completeness:true
4531 on_error)
4532 ~this_ty:None
4533 ty_sub
4534 ty_super
4537 decompose_subtype_add_prop env prop
4539 and decompose_subtype_add_prop env prop =
4540 match prop with
4541 | TL.Conj props ->
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'
4545 | TL.Disj _ ->
4546 let callable_pos = env.genv.callable_pos in
4547 Typing_log.log_prop
4549 (Pos_or_decl.of_raw_pos callable_pos)
4550 "decompose_subtype_add_prop"
4552 prop;
4554 | TL.IsSubtype (coerce, LoclType ty1, LoclType ty2) ->
4555 decompose_subtype_add_bound ~coerce env ty1 ty2
4556 | TL.IsSubtype _ ->
4557 failwith
4558 "Subtyping locl types should yield propositions involving locl types only."
4560 (* Decompose a general constraint *)
4561 and decompose_constraint
4562 (env : env)
4563 (ck : Ast_defs.constraint_kind)
4564 (ty_sub : locl_ty)
4565 (ty_super : locl_ty)
4566 on_error : env =
4567 (* constraints are caught based on reason, not error callback. Using unify_error *)
4568 match ck with
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
4584 * C<T1> <: T2
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
4589 * environment too.
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
4597 let add_constraint
4598 (env : env)
4599 (ck : Ast_defs.constraint_kind)
4600 (ty_sub : locl_ty)
4601 (ty_super : locl_ty)
4602 on_error : env =
4603 log_subtype
4604 ~level:1
4605 ~this_ty:None
4606 ~function_name:"add_constraint"
4608 ty_sub
4609 ty_super;
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
4615 else
4616 let rec iter n env =
4617 if n > constraint_iteration_limit then
4619 else
4620 let oldsize = Env.get_tpenv_size env in
4621 let env =
4622 List.fold_left
4623 (Env.get_generic_parameters env)
4624 ~init:env
4625 ~f:(fun env x ->
4626 List.fold_left
4627 (* TODO(T70068435) always using [] as args for now *)
4628 (Typing_set.elements (Env.get_lower_bounds env x []))
4629 ~init:env
4630 ~f:(fun env ty_sub' ->
4631 List.fold_left
4632 (* TODO(T70068435) always using [] as args for now *)
4633 (Typing_set.elements (Env.get_upper_bounds env x []))
4634 ~init:env
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
4640 else
4641 iter (n + 1) env
4643 iter 0 env
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 =
4653 log_subtype
4654 ~level:1
4655 ~this_ty:None
4656 ~function_name:"coercion"
4658 ty_sub
4659 ty_super;
4660 let old_env = env in
4661 let (env, prop) =
4662 simplify_subtype
4663 ~subtype_env:
4664 (make_subtype_env ~coerce:(Some TL.CoerceFromDynamic) on_error)
4665 ~this_ty:None
4666 ty_sub
4667 ty_super
4670 let (env, ty_err) =
4671 prop_to_env (LoclType ty_sub) (LoclType ty_super) env prop on_error
4673 ( (if Option.is_some ty_err then
4674 old_env
4675 else
4676 env),
4677 ty_err )
4679 let simplify_subtype_i ?(is_coeffect = false) env ty_sub ty_super ~on_error =
4680 simplify_subtype_i
4681 ~subtype_env:(make_subtype_env ~is_coeffect ~no_top_bottom:true on_error)
4682 ty_sub
4683 ty_super
4686 (*****************************************************************************)
4687 (* Exporting *)
4688 (*****************************************************************************)
4690 let sub_type_i env ?(is_coeffect = false) ty1 ty2 on_error =
4691 sub_type_i
4692 ~subtype_env:(make_subtype_env ~is_coeffect ~coerce:None on_error)
4697 let subtype_funs
4698 ~(check_return : bool)
4699 ~on_error
4700 (r_sub : Reason.t)
4701 (ft_sub : locl_fun_type)
4702 (r_super : Reason.t)
4703 (ft_super : locl_fun_type)
4704 env =
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
4710 let (env, prop) =
4711 simplify_subtype_funs
4712 ~subtype_env:(make_subtype_env ~coerce:(Some TL.CoerceToDynamic) on_error)
4713 ~check_return
4714 r_sub
4715 ft_sub
4716 r_super
4717 ft_super
4720 let (env, ty_err) =
4721 prop_to_env
4722 (LoclType (mk (r_sub, Tfun ft_sub)))
4723 (LoclType (mk (r_super, Tfun ft_super)))
4725 prop
4726 on_error
4728 ( (if Option.is_some ty_err then
4729 old_env
4730 else
4731 env),
4732 ty_err )
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 ()