solved some TODOs about Tgeneric type arguments (2)
[hiphop-php.git] / hphp / hack / src / typing / typing_subtype.ml
blob36de6fbd8bd719e869e741a062650e4a77a63206
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 Subst = Decl_subst
20 module TUtils = Typing_utils
21 module SN = Naming_special_names
22 module Phase = Typing_phase
23 module TL = Typing_logic
24 module Cls = Decl_provider.Class
25 module ITySet = Internal_type_set
26 module MakeType = Typing_make_type
27 module Partial = Partial_provider
28 module ShapeMap = Nast.ShapeMap
29 module ShapeSet = Ast_defs.ShapeSet
30 module Nast = Aast
32 type subtype_env = {
33 seen_generic_params: SSet.t option;
34 no_top_bottom: bool;
35 treat_dynamic_as_bottom: bool;
36 on_error: Errors.typing_error_callback;
39 let empty_seen = Some SSet.empty
41 let make_subtype_env
42 ?(seen_generic_params = empty_seen)
43 ?(no_top_bottom = false)
44 ?(treat_dynamic_as_bottom = false)
45 on_error =
46 { seen_generic_params; no_top_bottom; treat_dynamic_as_bottom; on_error }
48 let add_seen_generic subtype_env name =
49 match subtype_env.seen_generic_params with
50 | Some seen ->
51 { subtype_env with seen_generic_params = Some (SSet.add name seen) }
52 | None -> subtype_env
54 type reactivity_extra_info = {
55 method_info: (* method_name *) (string * (* is_static *) bool) option;
56 class_ty: phase_ty option;
57 parent_class_ty: phase_ty option;
60 let empty_extra_info =
61 { method_info = None; class_ty = None; parent_class_ty = None }
63 module ConditionTypes = struct
64 let try_get_class_for_condition_type (env : env) (ty : decl_ty) =
65 match TUtils.try_unwrap_class_type ty with
66 | None -> None
67 | Some (_, ((_, x) as sid), _) ->
68 begin
69 match Env.get_class env x with
70 | None -> None
71 | Some cls -> Some (sid, cls)
72 end
74 let try_get_method_from_condition_type
75 (env : env) (ty : decl_ty) (is_static : bool) (method_name : string) =
76 match try_get_class_for_condition_type env ty with
77 | Some (_, cls) ->
78 let get =
79 if is_static then
80 Cls.get_smethod
81 else
82 Cls.get_method
84 get cls method_name
85 | None -> None
87 let localize_condition_type (env : env) (ty : decl_ty) : locl_ty =
88 (* if condition type is generic - we cannot specify type argument in attribute.
89 For cases when we check if containing type is a subtype of condition type
90 if condition type is generic instantiate it with TAny's *)
91 let do_localize ty =
92 let ty =
93 match try_get_class_for_condition_type env ty with
94 | None -> ty
95 | Some (_, cls) when List.is_empty (Cls.tparams cls) -> ty
96 | Some (((p, _) as sid), cls) ->
97 let params =
98 List.map (Cls.tparams cls) ~f:(fun { tp_name = (p, x); _ } ->
99 (* TODO(T69551141) handle type arguments *)
100 MakeType.generic (Reason.Rwitness p) x)
102 let subst = Decl_instantiate.make_subst (Cls.tparams cls) [] in
103 let ty = MakeType.apply (Reason.Rwitness p) sid params in
104 Decl_instantiate.instantiate subst ty
106 let ety_env = Phase.env_with_self env in
107 let (_, t) = Phase.localize ~ety_env env ty in
110 match deref ty with
111 | (r, Toption ty) -> mk (r, Toption (do_localize ty))
112 | _ -> do_localize ty
115 (* Fetch all the constraints of a `Tpu_type_access(tparam, tyname)`, which
116 * are stored in a PU definition, and filter them to only keep upper bounds
118 let get_tpu_type_param_upper_bounds env tparam tyname =
119 (* Filter the decl type parameter constraints to only keep the `as` ones *)
120 let filter_constraints env ety_env decl_tparam =
121 List.filter_map_env env decl_tparam.tp_constraints ~f:(fun env (ck, dty) ->
122 match ck with
123 (* Only keep the "as" constraints *)
124 | Ast_defs.Constraint_as ->
125 let (env, lty) = Phase.localize ~ety_env env dty in
126 (env, Some lty)
127 | _ -> (env, None))
129 (* when tparam is bound by a Tpu(C, E), we look at the definition
130 * of the PU to get the constraints on `case type tyname`.
131 * We accumulate such constraints in `acc`
133 let get_case_type_constraints env cls enum acc =
134 (* Get the type parameter associated to tyname in this PU *)
135 let (env, info) = TUtils.class_get_pu_type env cls enum tyname in
136 let (env, ltys) =
137 match info with
138 | None -> (env, [])
139 | Some (ety_env, (_, decl_tparam)) ->
140 filter_constraints env ety_env decl_tparam
142 (env, List.rev_append acc ltys)
144 (* Get upper bounds of the tparam generic *)
145 let upper_bounds = Env.get_upper_bounds env tparam in
146 Typing_set.fold
147 (fun bound (env, acc) ->
148 match get_node bound with
149 (* Only inspect Tpu bounds *)
150 | Tpu (cls, (_, enum)) -> get_case_type_constraints env cls enum acc
151 | _ -> (env, acc))
152 upper_bounds
153 (env, [])
155 (* Given a pair of types `ty_sub` and `ty_super` attempt to apply simplifications
156 * and add to the accumulated constraints in `constraints` any necessary and
157 * sufficient [(t1,ck1,u1);...;(tn,ckn,un)] such that
158 * ty_sub <: ty_super iff t1 ck1 u1, ..., tn ckn un
159 * where ck is `as` or `=`. Essentially we are making solution-preserving
160 * simplifications to the subtype assertion, for now, also generating equalities
161 * as well as subtype assertions, for backwards compatibility with use of
162 * unification.
164 * If `constraints = []` is returned then the subtype assertion is valid.
166 * If the subtype assertion is unsatisfiable then return `failed = Some f`
167 * where `f` is a `unit-> unit` function that records an error message.
168 * (Sometimes we don't want to call this function e.g. when just checking if
169 * a subtype holds)
171 * Elide singleton unions, treat invariant generics as both-ways
172 * subtypes, and actually chase hierarchy for extends and implements.
174 * Annoyingly, we need to pass env back too, because Typing_phase.localize
175 * expands type constants. (TODO: work out a better way of handling this)
177 * Special cases:
178 * If assertion is valid (e.g. string <: arraykey) then
179 * result can be the empty list (i.e. nothing is added to the result)
180 * If assertion is unsatisfiable (e.g. arraykey <: string) then
181 * we record this in the failed field of the result.
184 (** Check that a mutability type is a subtype of another mutability type *)
185 let check_mutability
186 ~(is_receiver : bool)
187 ~subtype_env
188 (p_sub : Pos.t)
189 (mut_sub : param_mutability option)
190 (p_super : Pos.t)
191 (mut_super : param_mutability option)
192 env =
193 let str m =
194 match m with
195 | None -> "immutable"
196 | Some Param_owned_mutable -> "owned mutable"
197 | Some Param_borrowed_mutable -> "mutable"
198 | Some Param_maybe_mutable -> "maybe-mutable"
200 (* maybe-mutable <------immutable
202 <--mutable <-- owned mutable *)
203 match (mut_sub, mut_super) with
204 (* immutable is not compatible with mutable *)
205 | (None, Some (Param_borrowed_mutable | Param_owned_mutable))
206 (* mutable is not compatible with immutable *)
207 | (Some (Param_borrowed_mutable | Param_owned_mutable), None)
208 (* borrowed mutable is not compatible with owned mutable *)
209 | (Some Param_borrowed_mutable, Some Param_owned_mutable)
210 (* maybe-mutable is not compatible with immutable/mutable *)
211 | ( Some Param_maybe_mutable,
212 (None | Some (Param_borrowed_mutable | Param_owned_mutable)) ) ->
213 invalid
214 ~fail:(fun () ->
215 Errors.mutability_mismatch
216 ~is_receiver
217 p_sub
218 (str mut_sub)
219 p_super
220 (str mut_super)
221 subtype_env.on_error)
223 | _ -> valid env
225 let log_subtype_i ~level ~this_ty ~function_name env ty_sub ty_super =
226 Typing_log.(
227 log_with_level env "sub" level (fun () ->
228 let types =
229 [Log_type_i ("ty_sub", ty_sub); Log_type_i ("ty_super", ty_super)]
231 let types =
232 Option.value_map this_ty ~default:types ~f:(fun ty ->
233 Log_type ("this_ty", ty) :: types)
235 log_types
236 (Reason.to_pos (reason ty_sub))
238 [Log_head (function_name, types)]))
240 let log_subtype ~this_ty ~function_name env ty_sub ty_super =
241 log_subtype_i
242 ~this_ty
243 ~function_name
245 (LoclType ty_sub)
246 (LoclType ty_super)
248 let is_final_and_not_contravariant env id =
249 let class_def = Env.get_class env id in
250 match class_def with
251 | Some class_ty -> TUtils.class_is_final_and_not_contravariant class_ty
252 | None -> false
254 (** Make all types appearing in the given type a Tany, e.g.
255 - for A<B> return A<_>
256 - for function(A): B return function (_): _
258 let anyfy env r ty =
259 let anyfyer =
260 object
261 inherit Type_mapper.deep_type_mapper as super
263 method! on_type env _ty = (env, mk (r, Typing_defs.make_tany ()))
265 method go ty =
266 let (_, ty) = super#on_type env ty in
270 anyfyer#go ty
272 let find_type_with_exact_negation env tyl =
273 let rec find env tyl acc_tyl =
274 match tyl with
275 | [] -> (env, None, acc_tyl)
276 | ty :: tyl' ->
277 let (env, non_ty) = TUtils.non env (get_reason ty) ty TUtils.ApproxDown in
278 let nothing = MakeType.nothing Reason.none in
279 if ty_equal non_ty nothing then
280 find env tyl' (ty :: acc_tyl)
281 else
282 (env, Some non_ty, tyl' @ acc_tyl)
284 find env tyl []
286 let rec describe_ty_super env ?(short = false) ty =
287 let print ty =
288 Typing_print.with_blank_tyvars (fun () ->
289 Typing_print.full_strip_ns_i env ty)
291 let default () = print ty in
292 match ty with
293 | LoclType ty ->
294 let (env, ty) = Env.expand_type env ty in
295 (match get_node ty with
296 | Tvar v ->
297 let upper_bounds = ITySet.elements (Env.get_tyvar_upper_bounds env v) in
298 (* The constraint graph is transitively closed so we can filter tyvars. *)
299 let is_not_tyvar = function
300 | LoclType t -> not (is_tyvar t)
301 | _ -> true
303 let upper_bounds = List.filter upper_bounds ~f:is_not_tyvar in
304 (match upper_bounds with
305 | [] -> "some type not known yet"
306 | tyl ->
307 let (locl_tyl, cstr_tyl) = List.partition_tf tyl ~f:is_locl_type in
308 let prefix =
309 if short then
311 else
312 "something "
314 let sep =
315 match (locl_tyl, cstr_tyl) with
316 | (_ :: _, _ :: _) -> " and "
317 | _ -> ""
319 let locl_descr =
320 match locl_tyl with
321 | [] -> ""
322 | tyl ->
323 let prefix =
324 if short then
326 else
327 "of type "
329 prefix ^ String.concat ~sep:" & " (List.map tyl ~f:print)
331 let cstr_descr =
332 String.concat
333 ~sep:" and "
334 (List.map cstr_tyl ~f:(describe_ty_super env))
336 prefix ^ locl_descr ^ sep ^ cstr_descr)
337 | Toption ty when is_tyvar ty ->
338 "null or " ^ describe_ty_super env (LoclType ty)
339 | _ -> default ())
340 | ConstraintType ty ->
341 (match deref_constraint_type ty with
342 | (_, Thas_member hm) ->
343 let { hm_name = (_, name); hm_type = _; hm_class_id = _ } = hm in
344 Printf.sprintf "an object with member `%s`" name
345 | (_, Tdestructure _) ->
346 Typing_print.with_blank_tyvars (fun () ->
347 Typing_print.full_strip_ns_i env (ConstraintType ty))
348 | (_, TCunion (lty, cty)) ->
349 Printf.sprintf
350 "%s or %s"
351 (describe_ty_super env (LoclType lty))
352 (describe_ty_super env (ConstraintType cty))
353 | (_, TCintersection (lty, cty)) ->
354 Printf.sprintf
355 "%s and %s"
356 (describe_ty_super env (LoclType lty))
357 (describe_ty_super env (ConstraintType cty)))
359 (** Process the constraint proposition. There should only be errors left now,
360 i.e. empty disjunction with error functions we call here. *)
361 let rec process_simplify_subtype_result prop =
362 match prop with
363 | TL.IsSubtype (_ty1, _ty2) ->
364 (* All subtypes should have been resolved *)
365 failwith "unexpected subtype assertion"
366 | TL.Coerce _ ->
367 (* All coercions should have been resolved *)
368 failwith "unexpected coercions assertion"
369 | TL.Conj props ->
370 (* Evaluates list from left-to-right so preserves order of conjuncts *)
371 List.for_all ~f:process_simplify_subtype_result props
372 | TL.Disj (f, []) ->
373 f ();
374 false
375 | TL.Disj _ -> failwith "non-empty disjunction"
377 and simplify_subtype
378 ~(subtype_env : subtype_env)
379 ?(this_ty : locl_ty option = None)
380 ty_sub
381 ty_super =
382 simplify_subtype_i ~subtype_env ~this_ty (LoclType ty_sub) (LoclType ty_super)
384 (* Attempt to "solve" a subtype assertion ty_sub <: ty_super.
385 * Return a proposition that is equivalent, but simpler, than
386 * the original assertion. Fail with Unsat error_function if
387 * the assertion is unsatisfiable. Some examples:
388 * string <: arraykey ==> True (represented as Conj [])
389 * (For covariant C and a type variable v)
390 * C<string> <: C<v> ==> string <: v
391 * (Assuming that C does *not* implement interface J)
392 * C <: J ==> Unsat _
393 * (Assuming we have T <: D in tpenv, and class D implements I)
394 * vec<T> <: vec<I> ==> True
395 * This last one would be left as T <: I if seen_generic_params is None
397 and simplify_subtype_i
398 ~(subtype_env : subtype_env)
399 ?(this_ty : locl_ty option = None)
400 (ty_sub : internal_type)
401 (ty_super : internal_type)
402 env : env * TL.subtype_prop =
403 log_subtype_i
404 ~level:2
405 ~this_ty
406 ~function_name:"simplify_subtype"
408 ty_sub
409 ty_super;
410 let (env, ety_super) = Env.expand_internal_type env ty_super in
411 let (env, ety_sub) = Env.expand_internal_type env ty_sub in
412 let fail_with_suffix suffix =
413 let r_super = reason ety_super in
414 let r_sub = reason ety_sub in
415 let ty_super_descr = describe_ty_super env ety_super in
416 let ty_sub_descr =
417 Typing_print.with_blank_tyvars (fun () ->
418 Typing_print.full_strip_ns_i env ety_sub)
420 let (ty_super_descr, ty_sub_descr) =
421 if String.equal ty_super_descr ty_sub_descr then
422 ( "exactly the type " ^ ty_super_descr,
423 "the nonexact type " ^ ty_sub_descr )
424 else
425 (ty_super_descr, ty_sub_descr)
427 let left = Reason.to_string ("Expected " ^ ty_super_descr) r_super in
428 let right = Reason.to_string ("But got " ^ ty_sub_descr) r_sub @ suffix in
429 match (r_super, r_sub) with
430 | (Reason.Rcstr_on_generics (p, tparam), _)
431 | (_, Reason.Rcstr_on_generics (p, tparam)) ->
432 Errors.violated_constraint p tparam left right subtype_env.on_error
433 | _ -> subtype_env.on_error (left @ right)
435 let fail () = fail_with_suffix [] in
436 let ( ||| ) = ( ||| ) ~fail in
437 (* We *know* that the assertion is unsatisfiable *)
438 let invalid_with f = invalid ~fail:f env in
439 let invalid_env env = invalid ~fail env in
440 let invalid_env_with env f = invalid ~fail:f env in
441 let invalid () = invalid_with fail in
442 (* We *know* that the assertion is valid *)
443 let valid_env env = valid env in
444 let valid () = valid_env env in
445 (* We don't know whether the assertion is valid or not *)
446 let default () = (env, TL.IsSubtype (ety_sub, ety_super)) in
447 (* This function contains typing rules that are based solely on the subtype
448 * if you need to pattern match on the super type it should NOT be included
449 * here
451 let default_subtype env =
452 let ty_sub = ety_sub in
453 let ty_super = ety_super in
454 match ty_sub with
455 | ConstraintType cty_sub ->
456 begin
457 match deref_constraint_type cty_sub with
458 | (_, TCunion (lty_sub, cty_sub)) ->
460 |> simplify_subtype_i ~subtype_env (LoclType lty_sub) ty_super
461 &&& simplify_subtype_i ~subtype_env (ConstraintType cty_sub) ty_super
462 | (_, TCintersection (lty_sub, cty_sub)) ->
464 |> simplify_subtype_i ~subtype_env (LoclType lty_sub) ty_super
465 ||| simplify_subtype_i ~subtype_env (ConstraintType cty_sub) ty_super
466 | _ -> invalid ()
468 | LoclType ty_sub ->
470 * t1 | ... | tn <: t
471 * if and only if
472 * t1 <: t /\ ... /\ tn <: t
473 * We want this even if t is a type variable e.g. consider
474 * int | v <: v
476 begin
477 match deref ty_sub with
478 | (_, Tunion tyl) ->
479 List.fold_left tyl ~init:(env, TL.valid) ~f:(fun res ty_sub ->
480 res &&& simplify_subtype_i ~subtype_env (LoclType ty_sub) ty_super)
481 | (_, Terr) ->
482 if subtype_env.no_top_bottom then
483 default ()
484 else
485 valid ()
486 | (_, Tvar _) -> default ()
487 | (r_sub, Tintersection tyl) ->
488 (* A & B <: C iif A <: C | !B *)
489 (match find_type_with_exact_negation env tyl with
490 | (env, Some non_ty, tyl) ->
491 let (env, ty_super) =
492 TUtils.union_i env (get_reason non_ty) ty_super non_ty
494 let ty_sub = MakeType.intersection r_sub tyl in
495 simplify_subtype_i ~subtype_env (LoclType ty_sub) ty_super env
496 | _ ->
497 (* It's sound to reduce t1 & t2 <: t to (t1 <: t) || (t2 <: t), but
498 * not complete.
500 List.fold_left
502 ~init:(env, TL.invalid ~fail)
503 ~f:(fun res ty_sub ->
504 let ty_sub = LoclType ty_sub in
505 res ||| simplify_subtype_i ~subtype_env ~this_ty ty_sub ty_super))
506 | (_, Tgeneric (name_sub, _tyargs)) ->
507 (* TODO(T69551141) handle type arguments *)
508 (match subtype_env.seen_generic_params with
509 | None -> default ()
510 | Some seen ->
511 (* If we've seen this type parameter before then we must have gone
512 * round a cycle so we fail
514 if SSet.mem name_sub seen then
515 invalid ()
516 else
517 (* If the generic is actually an expression dependent type,
518 we need to update this_ty
520 let this_ty =
522 DependentKind.is_generic_dep_ty name_sub
523 && Option.is_none this_ty
524 then
525 Some ty_sub
526 else
527 this_ty
529 let subtype_env = add_seen_generic subtype_env name_sub in
530 (* Otherwise, we collect all the upper bounds ("as" constraints) on
531 the generic parameter, and check each of these in turn against
532 ty_super until one of them succeeds
534 let rec try_bounds tyl env =
535 match tyl with
536 | [] ->
537 (* Try an implicit mixed = ?nonnull bound before giving up.
538 This can be useful when checking T <: t, where type t is
539 equivalent to but syntactically different from ?nonnull.
540 E.g., if t is a generic type parameter T with nonnull as
541 a lower bound.
543 let r =
544 Reason.Rimplicit_upper_bound (get_pos ty_sub, "?nonnull")
546 let tmixed = LoclType (MakeType.mixed r) in
548 |> simplify_subtype_i ~subtype_env ~this_ty tmixed ty_super
549 | [ty] ->
550 simplify_subtype_i
551 ~subtype_env
552 ~this_ty
553 (LoclType ty)
554 ty_super
556 | ty :: tyl ->
558 |> try_bounds tyl
559 ||| simplify_subtype_i
560 ~subtype_env
561 ~this_ty
562 (LoclType ty)
563 ty_super
566 |> try_bounds
567 (Typing_set.elements (Env.get_upper_bounds env name_sub)))
568 |> (* Turn error into a generic error about the type parameter *)
569 if_unsat invalid
570 | (_, Tdynamic) when subtype_env.treat_dynamic_as_bottom -> valid ()
571 | (_, Tpu_type_access ((_pm, msub), (_pn, nsub))) ->
572 (* If member is actually an expression dependent type,
573 * we need to update this_ty
575 let this_ty =
576 if DependentKind.is_generic_dep_ty msub && Option.is_none this_ty
577 then
578 Some ty_sub
579 else
580 this_ty
583 * We are checking if msub:@nsub is a subtype of ty_super.
584 * Since msub is a generic parameter, we are scanning all of its
585 * upper bounds and look for all C:@E.
586 * We then scan the PU definition of these C:@E to gather the 'as'
587 * constraints on the type `case type nsub`.
589 * Finally, we attempt to use those in recursive subtype calls
590 * to check if they are <: ty_super.
592 let (env, upper_bounds) =
593 get_tpu_type_param_upper_bounds env msub nsub
595 let rec try_bounds tyl env =
596 match tyl with
597 | [] -> invalid_env env
598 | [ty] ->
599 simplify_subtype_i
600 ~subtype_env
601 ~this_ty
602 (LoclType ty)
603 ty_super
605 | ty :: tyl ->
607 |> try_bounds tyl
608 ||| simplify_subtype_i
609 ~subtype_env
610 ~this_ty
611 (LoclType ty)
612 ty_super
614 env |> try_bounds upper_bounds |> if_unsat invalid
615 | _ -> invalid ()
618 (* We further refine the default subtype case for rules that apply to all
619 * LoclTypes but not to ConstraintTypes
621 let default_subtype env =
622 let ty_sub = ety_sub in
623 let ty_super = ety_super in
624 match ty_super with
625 | LoclType ty_super ->
626 (match ty_sub with
627 | ConstraintType _ -> default_subtype env
628 | LoclType ty_sub ->
629 begin
630 match deref ty_sub with
631 | (_, Tvar _) when subtype_env.treat_dynamic_as_bottom ->
632 (env, TL.Coerce (ty_sub, ty_super))
633 | (_, Tnewtype (_, _, ty)) ->
634 simplify_subtype ~subtype_env ~this_ty ty ty_super env
635 | (_, Tdependent (_, ty)) ->
636 let this_ty = Option.first_some this_ty (Some ty_sub) in
637 simplify_subtype ~subtype_env ~this_ty ty ty_super env
638 | (r_sub, Tany _) ->
639 if subtype_env.no_top_bottom then
640 default ()
641 else
642 let ty_sub = anyfy env r_sub ty_super in
643 simplify_subtype ~subtype_env ~this_ty ty_sub ty_super env
644 | (r_sub, Tprim Nast.Tvoid) ->
645 let r =
646 Reason.Rimplicit_upper_bound (Reason.to_pos r_sub, "?nonnull")
648 simplify_subtype
649 ~subtype_env
650 ~this_ty
651 (MakeType.mixed r)
652 ty_super
654 |> if_unsat invalid
655 | _ -> default_subtype env
656 end)
657 | ConstraintType _ -> default_subtype env
659 match ety_super with
660 (* First deal with internal constraint types *)
661 | ConstraintType cty_super ->
662 begin
663 match deref_constraint_type cty_super with
664 | (_, TCintersection (lty, cty)) ->
665 (match ety_sub with
666 | LoclType t when is_union t -> default_subtype env
667 | ConstraintType t when is_constraint_type_union t ->
668 default_subtype env
669 | _ ->
671 |> simplify_subtype_i ~subtype_env ty_sub (LoclType lty)
672 &&& simplify_subtype_i ~subtype_env ty_sub (ConstraintType cty))
673 | (_, TCunion (lty_super, cty_super)) ->
674 (match ety_sub with
675 | ConstraintType cty when is_constraint_type_union cty ->
676 default_subtype env
677 | ConstraintType _ ->
679 |> simplify_subtype_i ~subtype_env ty_sub (LoclType lty_super)
680 ||| simplify_subtype_i ~subtype_env ty_sub (ConstraintType cty_super)
681 ||| default_subtype
682 | LoclType lty ->
683 (match deref lty with
684 | (r, Toption ty) ->
685 let ty_null = MakeType.null r in
686 let (env, p1) =
687 simplify_subtype_i
688 ~subtype_env
689 ~this_ty
690 (LoclType ty_null)
691 ty_super
694 if TL.is_unsat p1 then
695 invalid ()
696 else
697 let (env, p2) =
698 simplify_subtype_i
699 ~subtype_env
700 ~this_ty
701 (LoclType ty)
702 ty_super
705 (env, TL.conj p1 p2)
706 | (_, (Tintersection _ | Tunion _ | Terr | Tvar _)) ->
707 default_subtype env
708 | _ ->
710 |> simplify_subtype_i ~subtype_env ty_sub (LoclType lty_super)
711 ||| simplify_subtype_i
712 ~subtype_env
713 ty_sub
714 (ConstraintType cty_super)
715 ||| default_subtype))
716 | (r_super, Tdestructure { d_required; d_optional; d_variadic; d_kind })
718 (* List destructuring *)
719 let destructure_array t env =
720 (* If this is a splat, there must be a variadic box to receive the elements
721 * but for list(...) destructuring this is not required. Example:
723 * function f(int $i): void {}
724 * function g(vec<int> $v): void {
725 * list($a) = $v; // ok (but may throw)
726 * f(...$v); // error
727 * } *)
728 let fpos =
729 match r_super with
730 | Reason.Runpack_param (_, fpos, _) -> fpos
731 | _ -> Reason.to_pos r_super
733 match (d_kind, d_required, d_variadic) with
734 | (SplatUnpack, _ :: _, _) ->
735 (* return the env so as not to discard the type variable that might
736 have been created for the Traversable type created below. *)
737 invalid_env_with env (fun () ->
738 Errors.unpack_array_required_argument
739 (Reason.to_pos r_super)
740 fpos
741 subtype_env.on_error)
742 | (SplatUnpack, [], None) ->
743 invalid_env_with env (fun () ->
744 Errors.unpack_array_variadic_argument
745 (Reason.to_pos r_super)
746 fpos
747 subtype_env.on_error)
748 | (SplatUnpack, [], Some _)
749 | (ListDestructure, _, _) ->
750 List.fold d_required ~init:(env, TL.valid) ~f:(fun res ty_dest ->
751 res &&& simplify_subtype ~subtype_env ~this_ty t ty_dest)
752 &&& fun env ->
753 List.fold d_optional ~init:(env, TL.valid) ~f:(fun res ty_dest ->
754 res &&& simplify_subtype ~subtype_env ~this_ty t ty_dest)
755 &&& fun env ->
756 Option.value_map ~default:(env, TL.valid) d_variadic ~f:(fun vty ->
757 simplify_subtype ~subtype_env ~this_ty t vty env)
760 let destructure_tuple r ts env =
761 (* First fill the required elements. If there are insufficient elements, an error is reported.
762 * Fill as many of the optional elements as possible, and the remainder are unioned into the
763 * variadic element. Example:
765 * (float, bool, string, int) <: Tdestructure(#1, opt#2, ...#3) =>
766 * float <: #1 /\ bool <: #2 /\ string <: #3 /\ int <: #3
768 * (float, bool) <: Tdestructure(#1, #2, opt#3) =>
769 * float <: #1 /\ bool <: #2
771 let len_ts = List.length ts in
772 let len_required = List.length d_required in
773 let arity_error f =
774 let (epos, fpos, prefix) =
775 match r_super with
776 | Reason.Runpack_param (epos, fpos, c) -> (epos, fpos, c)
777 | _ -> (Reason.to_pos r_super, Reason.to_pos r, 0)
779 invalid_env_with env (fun () ->
781 (prefix + len_required)
782 (prefix + len_ts)
783 epos
784 fpos
785 (Some subtype_env.on_error))
787 if len_ts < len_required then
788 arity_error Errors.typing_too_few_args
789 else
790 let len_optional = List.length d_optional in
791 let (ts_required, remain) = List.split_n ts len_required in
792 let (ts_optional, ts_variadic) = List.split_n remain len_optional in
793 List.fold2_exn
794 ts_required
795 d_required
796 ~init:(env, TL.valid)
797 ~f:(fun res ty ty_dest ->
798 res &&& simplify_subtype ~subtype_env ~this_ty ty ty_dest)
799 &&& fun env ->
800 let len_ts_opt = List.length ts_optional in
801 let d_optional_part =
802 if len_ts_opt < len_optional then
803 List.take d_optional len_ts_opt
804 else
805 d_optional
807 List.fold2_exn
808 ts_optional
809 d_optional_part
810 ~init:(env, TL.valid)
811 ~f:(fun res ty ty_dest ->
812 res &&& simplify_subtype ~subtype_env ~this_ty ty ty_dest)
813 &&& fun env ->
814 match (ts_variadic, d_variadic) with
815 | (vars, Some vty) ->
816 List.fold vars ~init:(env, TL.valid) ~f:(fun res ty ->
817 res &&& simplify_subtype ~subtype_env ~this_ty ty vty)
818 | ([], None) -> valid ()
819 | (_, None) ->
820 (* Elements remain but we have nowhere to put them *)
821 arity_error Errors.typing_too_many_args
824 begin
825 match ety_sub with
826 | ConstraintType _ -> default_subtype env
827 | LoclType ty_sub ->
828 (match deref ty_sub with
829 | (r, Ttuple tyl) -> env |> destructure_tuple r tyl
830 | (r, Tclass ((_, x), _, tyl))
831 when String.equal x SN.Collections.cPair ->
832 env |> destructure_tuple r tyl
833 | (_, Tclass ((_, x), _, [elt_type]))
834 when String.equal x SN.Collections.cVector
835 || String.equal x SN.Collections.cImmVector
836 || String.equal x SN.Collections.cVec
837 || String.equal x SN.Collections.cConstVector ->
838 env |> destructure_array elt_type
839 | (_, Tvarray elt_type) -> env |> destructure_array elt_type
840 | (_, Tdynamic) -> env |> destructure_array ty_sub
841 (* TODO: should remove these any cases *)
842 | (r, Tany _) ->
843 let any = mk (r, Typing_defs.make_tany ()) in
844 env |> destructure_array any
845 | (_, (Tunion _ | Tintersection _ | Tgeneric _ | Tvar _)) ->
846 (* TODO(T69551141) handle type arguments of Tgeneric? *)
847 default_subtype env
848 | _ ->
849 begin
850 match d_kind with
851 | SplatUnpack ->
852 (* Allow splatting of arbitrary Traversables *)
853 let (env, ty_inner) =
854 Env.fresh_type env (Reason.to_pos r_super)
856 let traversable = MakeType.traversable r_super ty_inner in
858 |> simplify_subtype ~subtype_env ~this_ty ty_sub traversable
859 &&& destructure_array ty_inner
860 | ListDestructure ->
861 let ty_sub_descr =
862 Typing_print.with_blank_tyvars (fun () ->
863 Typing_print.full_strip_ns env ty_sub)
865 default_subtype env
866 |> if_unsat @@ fun () ->
867 invalid_with (fun () ->
868 Errors.invalid_destructure
869 (Reason.to_pos r_super)
870 (get_pos ty_sub)
871 ty_sub_descr
872 subtype_env.on_error)
873 end)
875 | ( r,
876 Thas_member
877 { hm_name = name; hm_type = member_ty; hm_class_id = class_id } ) ->
878 (match ety_sub with
879 | ConstraintType cty ->
880 begin
881 match deref_constraint_type cty with
882 | ( _,
883 Thas_member
885 hm_name = name_sub;
886 hm_type = ty_sub;
887 hm_class_id = cid_sub;
888 } ) ->
889 if Nast.equal_sid name_sub name && class_id_equal cid_sub class_id
890 then
891 simplify_subtype ~subtype_env ~this_ty ty_sub member_ty env
892 else
893 invalid ()
894 | _ -> default_subtype env
896 | LoclType ty_sub ->
897 (match deref ty_sub with
898 | (_, (Tvar _ | Tunion _ | Terr)) -> default_subtype env
899 | (_, Tintersection tyl)
900 when let (_, non_ty_opt, _) =
901 find_type_with_exact_negation env tyl
903 Option.is_some non_ty_opt ->
904 default_subtype env
905 (* Ideally, we'd want this case to come after the case with an intersection
906 on the left, to deal properly with (#1 & A) <: Thas_member(#2) by potentially
907 adding an upper bound to #1, but that would result in a disjunction
908 which we don't handle very well at the moment.
909 TODO: when we have a better treatment of disjunctions, move that case after
910 the case with an intersection on the left.
911 For now, if there is an intersection on the left here,
912 we rely on how obj_get itself treats intersections. If that
913 intersection contains a type variable, this type variable will be eagerly
914 solved. Once this case is moved, we can clean up obj_get from the Tvar and
915 Tintersection cases *)
916 | _ ->
917 let (obj_get_ty, error_prop) =
918 Errors.try_with_result
919 (fun () ->
920 let (env, (obj_get_ty, _tal)) =
921 Typing_object_get.obj_get
922 ~obj_pos:(Reason.to_pos r)
923 ~is_method:false
924 ~coerce_from_ty:None
925 ~nullsafe:None
926 ~explicit_targs:[]
928 ty_sub
929 class_id
930 name
931 subtype_env.on_error
933 (obj_get_ty, valid_env env))
934 (fun (obj_get_ty, _) error ->
935 (obj_get_ty, invalid_with (fun () -> Errors.add_error error)))
937 error_prop
938 &&& simplify_subtype ~subtype_env ~this_ty obj_get_ty member_ty))
940 (* Next deal with all locl types *)
941 | LoclType ty_super ->
942 (match deref ty_super with
943 | (_, Terr) ->
944 (match ety_sub with
945 | ConstraintType cty when is_constraint_type_union cty ->
946 default_subtype env
947 | ConstraintType _ ->
948 if subtype_env.no_top_bottom then
949 default ()
950 else
951 valid ()
952 | LoclType lty ->
953 (match deref lty with
954 | (_, Tunion _) -> default_subtype env
955 | (_, Terr) -> valid ()
956 | _ ->
957 if subtype_env.no_top_bottom then
958 default ()
959 else
960 valid ()))
961 | (_, Tvar var_super) ->
962 (match ety_sub with
963 | ConstraintType cty when is_constraint_type_union cty ->
964 default_subtype env
965 | ConstraintType _ -> default ()
966 | LoclType ty_sub ->
967 (match deref ty_sub with
968 | (_, (Tunion _ | Terr)) -> default_subtype env
969 | (_, Tdynamic) when subtype_env.treat_dynamic_as_bottom ->
970 default_subtype env
971 (* We want to treat nullable as a union with the same rule as above.
972 * This is only needed for Tvar on right; other cases are dealt with specially as
973 * derived rules.
975 | (r, Toption t) ->
976 let ty_null = MakeType.null r in
978 |> simplify_subtype ~subtype_env ~this_ty t ty_super
979 &&& simplify_subtype ~subtype_env ~this_ty ty_null ty_super
980 | (_, Tvar var_sub) when Ident.equal var_sub var_super -> valid ()
981 | _ when subtype_env.treat_dynamic_as_bottom ->
982 (env, TL.Coerce (ty_sub, ty_super))
983 | _ -> default ()))
984 | (_, Tintersection tyl) ->
985 (match ety_sub with
986 | ConstraintType cty when is_constraint_type_union cty ->
987 default_subtype env
988 | LoclType lty when is_union lty -> default_subtype env
989 (* t <: (t1 & ... & tn)
990 * if and only if
991 * t <: t1 /\ ... /\ t <: tn
993 | _ ->
994 List.fold_left tyl ~init:(env, TL.valid) ~f:(fun res ty_super ->
995 let ty_super = LoclType ty_super in
996 res &&& simplify_subtype_i ~subtype_env ~this_ty ty_sub ty_super))
997 (* Empty union encodes the bottom type nothing *)
998 | (_, Tunion []) -> default_subtype env
999 (* ty_sub <: union{ty_super'} iff ty_sub <: ty_super' *)
1000 | (_, Tunion [ty_super']) ->
1001 simplify_subtype_i ~subtype_env ~this_ty ty_sub (LoclType ty_super') env
1002 | (_, Tunion (_ :: _ as tyl_super)) ->
1003 let simplify_sub_union env ty_sub tyl_super =
1004 (* It's sound to reduce t <: t1 | t2 to (t <: t1) || (t <: t2). But
1005 * not complete e.g. consider (t1 | t3) <: (t1 | t2) | (t2 | t3).
1006 * But we deal with unions on the left first (see case above), so this
1007 * particular situation won't arise.
1008 * TODO: identify under what circumstances this reduction is complete.
1010 let rec try_each tys env =
1011 match tys with
1012 | [] ->
1013 (match ty_sub with
1014 | LoclType lty ->
1015 begin
1016 match get_node lty with
1017 | Tnewtype _
1018 | Tdependent _
1019 | Tgeneric _ ->
1020 default_subtype env
1021 | _ -> invalid ()
1023 | _ -> invalid ())
1024 | ty :: tys ->
1025 let ty = LoclType ty in
1027 |> simplify_subtype_i ~subtype_env ~this_ty ty_sub ty
1028 ||| try_each tys
1030 try_each tyl_super env
1032 (match ety_sub with
1033 | ConstraintType cty when is_constraint_type_union cty ->
1034 default_subtype env
1035 | ConstraintType _ -> simplify_sub_union env ty_sub tyl_super
1036 | LoclType lty_sub ->
1037 (match deref lty_sub with
1038 | (_, (Tunion _ | Terr | Tvar _)) -> default_subtype env
1039 | (_, Tgeneric _) when Option.is_none subtype_env.seen_generic_params ->
1040 default_subtype env
1041 (* Num is not atomic: it is equivalent to int|float. The rule below relies
1042 * on ty_sub not being a union e.g. consider num <: arraykey | float, so
1043 * we break out num first.
1045 | (r, Tprim Nast.Tnum) ->
1046 let ty_float = MakeType.float r and ty_int = MakeType.int r in
1048 |> simplify_subtype ~subtype_env ~this_ty ty_float ty_super
1049 &&& simplify_subtype ~subtype_env ~this_ty ty_int ty_super
1050 (* Likewise, reduce nullable on left to a union *)
1051 | (r, Toption ty) ->
1052 let ty_null = MakeType.null r in
1053 let (env, p1) =
1054 simplify_subtype_i
1055 ~subtype_env
1056 ~this_ty
1057 (LoclType ty_null)
1058 ety_super
1061 if TL.is_unsat p1 then
1062 invalid ()
1063 else
1064 let (env, p2) =
1065 simplify_subtype_i
1066 ~subtype_env
1067 ~this_ty
1068 (LoclType ty)
1069 ety_super
1072 (env, TL.conj p1 p2)
1073 | (_, Tintersection tyl)
1074 when let (_, non_ty_opt, _) = find_type_with_exact_negation env tyl in
1075 Option.is_some non_ty_opt ->
1076 default_subtype env
1077 | (_, Tintersection tyl_sub) ->
1078 let simplify_super_intersection env tyl_sub ty_super =
1079 (* It's sound to reduce t1 & t2 <: t to (t1 <: t) || (t2 <: t), but
1080 * not complete.
1082 List.fold_left
1083 tyl_sub
1084 ~init:(env, TL.invalid ~fail)
1085 ~f:(fun res ty_sub ->
1086 let ty_sub = LoclType ty_sub in
1087 res ||| simplify_subtype_i ~subtype_env ~this_ty ty_sub ty_super)
1089 (* Heuristicky logic to decide whether to "break" the intersection
1090 or the union first, based on observing that the following cases often occur:
1091 - A & B <: (A & B) | C
1092 In which case we want to "break" the union on the right first
1093 in order to have the following recursive calls :
1094 A & B <: A & B
1095 A & B <: C
1096 - A & (B | C) <: B | C
1097 In which case we want to "break" the intersection on the left first
1098 in order to have the following recursive calls:
1099 A <: B | C
1100 B | C <: B | C
1102 if List.exists tyl_super ~f:(Typing_utils.is_tintersection env) then
1103 simplify_sub_union env ty_sub tyl_super
1104 else if List.exists tyl_sub ~f:(Typing_utils.is_tunion env) then
1105 simplify_super_intersection env tyl_sub (LoclType ty_super)
1106 else
1107 simplify_sub_union env ty_sub tyl_super
1108 | _ -> simplify_sub_union env ty_sub tyl_super))
1109 | (r_super, Toption arg_ty_super) ->
1110 let (env, ety) = Env.expand_type env arg_ty_super in
1111 (* Toption(Tnonnull) encodes mixed, which is our top type.
1112 * Everything subtypes mixed *)
1113 if is_nonnull ety then
1114 valid ()
1115 else (
1116 match ety_sub with
1117 | ConstraintType _ -> default_subtype env
1118 | LoclType lty_sub ->
1119 (match (deref lty_sub, get_node ety) with
1120 | ((_, Tnewtype (name_sub, _, _)), Tnewtype (name_sup, _, _))
1121 when String.equal name_sup name_sub ->
1122 simplify_subtype ~subtype_env ~this_ty lty_sub arg_ty_super env
1123 (* A <: ?B iif A & nonnull <: B
1124 Only apply if B is a type variable or an intersection, to avoid oscillating
1125 forever between this case and the previous one. *)
1126 | ((_, Tintersection tyl), (Tintersection _ | Tvar _))
1127 when let (_, non_ty_opt, _) =
1128 find_type_with_exact_negation env tyl
1130 Option.is_none non_ty_opt ->
1131 let (env, ty_sub') =
1132 Inter.intersect_i env r_super ty_sub (MakeType.nonnull r_super)
1134 simplify_subtype_i ~subtype_env ty_sub' (LoclType arg_ty_super) env
1135 (* null is the type of null and is a subtype of any option type. *)
1136 | ((_, Tprim Nast.Tnull), _) -> valid ()
1137 (* ?ty_sub' <: ?ty_super' iff ty_sub' <: ?ty_super'. Reasoning:
1138 * If ?ty_sub' <: ?ty_super', then from ty_sub' <: ?ty_sub' (widening) and transitivity
1139 * of <: it follows that ty_sub' <: ?ty_super'. Conversely, if ty_sub' <: ?ty_super', then
1140 * by covariance and idempotence of ?, we have ?ty_sub' <: ??ty_sub' <: ?ty_super'.
1141 * Therefore, this step preserves the set of solutions.
1143 | ((_, Toption ty_sub'), _) ->
1144 simplify_subtype ~subtype_env ~this_ty ty_sub' ty_super env
1145 (* We do not want to decompose Toption for these cases *)
1146 | ((_, (Tvar _ | Tunion _ | Tintersection _)), _) ->
1147 default_subtype env
1148 | ((_, Tgeneric _), _)
1149 when Option.is_none subtype_env.seen_generic_params ->
1150 (* TODO(T69551141) handle type arguments ? *)
1151 default_subtype env
1152 (* If t1 <: ?t2 and t1 is an abstract type constrained as t1',
1153 * then t1 <: t2 or t1' <: ?t2. The converse is obviously
1154 * true as well. We can fold the case where t1 is unconstrained
1155 * into the case analysis below.
1157 | ((_, (Tnewtype _ | Tdependent _ | Tgeneric _ | Tprim Nast.Tvoid)), _)
1159 (* TODO(T69551141) handle type arguments? *)
1161 |> simplify_subtype ~subtype_env ~this_ty lty_sub arg_ty_super
1162 ||| default_subtype
1163 (* If ty_sub <: ?ty_super' and ty_sub does not contain null then we
1164 * must also have ty_sub <: ty_super'. The converse follows by
1165 * widening and transitivity. Therefore, this step preserves the set
1166 * of solutions.
1168 | ( ( _,
1169 ( Tdynamic | Tprim _ | Tnonnull | Tfun _ | Ttuple _ | Tshape _
1170 | Tobject | Tclass _ | Tvarray _ | Tdarray _
1171 | Tvarray_or_darray _ | Tany _ | Terr | Tpu _
1172 | Tpu_type_access _ ) ),
1173 _ ) ->
1174 simplify_subtype ~subtype_env ~this_ty lty_sub arg_ty_super env)
1176 | (r_super, Tdependent (d_sup, bound_sup)) ->
1177 let (env, bound_sup) = Env.expand_type env bound_sup in
1178 (match ety_sub with
1179 | ConstraintType _ -> default_subtype env
1180 | LoclType ty_sub ->
1181 (match (deref ty_sub, get_node bound_sup) with
1182 | ((_, Tclass _), Tclass ((_, x), _, _))
1183 when is_final_and_not_contravariant env x ->
1184 (* For final class C, there is no difference between `this as X` and `X`,
1185 * and `expr<#n> as X` and `X`.
1186 * But we need to take care with contravariant classes, since we can't
1187 * statically guarantee their runtime type.
1189 simplify_subtype ~subtype_env ~this_ty ty_sub bound_sup env
1190 | ((r_sub, Tclass ((_, y), _, _)), Tclass (((_, x) as id), _, tyl_super))
1192 let fail =
1193 if String.equal x y then
1194 fun () ->
1195 let p = Reason.to_pos r_sub in
1196 fail_with_suffix
1197 ( if equal_dependent_type d_sup (DTcls x) then
1198 Errors.exact_class_final id p
1199 else
1200 Errors.this_final id p )
1201 else
1202 fail
1205 let class_def = Env.get_class env x in
1206 (match (d_sup, class_def) with
1207 | (DTthis, Some class_ty) ->
1208 let tyl_super =
1210 List.is_empty tyl_super
1211 && not (Partial.should_check_error (Env.get_mode env) 4029)
1212 then
1213 List.map (Cls.tparams class_ty) (fun _ ->
1214 mk (r_super, Typing_defs.make_tany ()))
1215 else
1216 tyl_super
1220 (Int.equal
1221 (List.length (Cls.tparams class_ty))
1222 (List.length tyl_super))
1223 then
1224 invalid_with (fun () ->
1225 Errors.expected_tparam
1226 ~definition_pos:(Cls.pos class_ty)
1227 ~use_pos:(Reason.to_pos r_super)
1228 (List.length (Cls.tparams class_ty))
1229 (Some subtype_env.on_error))
1230 else
1231 let ety_env =
1233 type_expansions = [];
1234 substs = Subst.make_locl (Cls.tparams class_ty) tyl_super;
1235 this_ty = Option.value this_ty ~default:ty_super;
1236 from_class = None;
1237 on_error = subtype_env.on_error;
1238 quiet = true;
1241 let lower_bounds_super = Cls.lower_bounds_on_this class_ty in
1242 let rec try_constraints lower_bounds_super env =
1243 match lower_bounds_super with
1244 | [] -> invalid_with fail
1245 | ty_super :: lower_bounds_super ->
1246 let (env, ty_super) = Phase.localize ~ety_env env ty_super in
1248 |> simplify_subtype ~subtype_env ~this_ty ty_sub ty_super
1249 ||| try_constraints lower_bounds_super
1251 try_constraints lower_bounds_super env
1252 | _ -> invalid_with fail)
1253 | ((_, Tdependent (d_sub, bound_sub)), _) ->
1254 let this_ty = Option.first_some this_ty (Some ty_sub) in
1255 (* Dependent types are identical but bound might be different *)
1256 if equal_dependent_type d_sub d_sup then
1257 simplify_subtype ~subtype_env ~this_ty bound_sub bound_sup env
1258 else
1259 simplify_subtype ~subtype_env ~this_ty bound_sub ty_super env
1260 | _ -> default_subtype env))
1261 | (_, Tgeneric (name_super, _tyargs)) ->
1262 (* TODO(T69551141) handle type arguments *)
1263 (match ety_sub with
1264 | ConstraintType _ -> default_subtype env
1265 (* If subtype and supertype are the same generic parameter, we're done *)
1266 | LoclType ty_sub ->
1267 (match get_node ty_sub with
1268 | Tgeneric (name_sub, _tyargs) when String.equal name_sub name_super ->
1269 valid ()
1270 (* TODO(T69551141) handle type arguments *)
1271 (* When decomposing subtypes for the purpose of adding bounds on generic
1272 * parameters to the context, (so seen_generic_params = None), leave
1273 * subtype so that the bounds get added *)
1274 | Tvar _
1275 | Tunion _
1276 | Terr ->
1277 default_subtype env
1278 | _ ->
1279 (match subtype_env.seen_generic_params with
1280 | None -> default ()
1281 | Some seen ->
1282 (* If we've seen this type parameter before then we must have gone
1283 * round a cycle so we fail
1285 if SSet.mem name_super seen then
1286 invalid ()
1287 else
1288 let subtype_env = add_seen_generic subtype_env name_super in
1289 (* Collect all the lower bounds ("super" constraints) on the
1290 * generic parameter, and check ty_sub against each of them in turn
1291 * until one of them succeeds *)
1292 let rec try_bounds tyl env =
1293 match tyl with
1294 | [] -> default_subtype env
1295 | ty :: tyl ->
1297 |> simplify_subtype ~subtype_env ~this_ty ty_sub ty
1298 ||| try_bounds tyl
1300 (* Turn error into a generic error about the type parameter *)
1302 |> try_bounds
1303 (Typing_set.elements (Env.get_lower_bounds env name_super))
1304 |> if_unsat invalid)))
1305 | (_, Tnonnull) ->
1306 (match ety_sub with
1307 | ConstraintType cty ->
1308 begin
1309 match deref_constraint_type cty with
1310 | (_, (Thas_member _ | Tdestructure _)) -> valid ()
1311 | _ -> default_subtype env
1313 | LoclType lty ->
1314 (match deref lty with
1315 | ( _,
1316 ( Tprim
1317 Nast.(
1318 ( Tint | Tbool | Tfloat | Tstring | Tresource | Tnum
1319 | Tarraykey | Tnoreturn | Tatom _ ))
1320 | Tnonnull | Tfun _ | Ttuple _ | Tshape _ | Tobject | Tclass _
1321 | Tvarray _ | Tdarray _ | Tvarray_or_darray _ | Tpu _
1322 | Tpu_type_access _ ) ) ->
1323 valid ()
1324 | _ -> default_subtype env))
1325 | (_, Tdynamic) ->
1326 (match ety_sub with
1327 | LoclType lty when is_dynamic lty -> valid ()
1328 | ConstraintType _
1329 | LoclType _ ->
1330 default_subtype env)
1331 | (_, Tprim prim_ty) ->
1332 (match ety_sub with
1333 | ConstraintType _ -> default_subtype env
1334 | LoclType lty ->
1335 (match (deref lty, prim_ty) with
1336 | ((_, Tprim (Nast.Tint | Nast.Tfloat)), Nast.Tnum) -> valid ()
1337 | ((_, Tprim (Nast.Tatom _)), Nast.Tstring) -> valid ()
1338 | ((_, Tpu (_, _)), Nast.Tstring) -> valid ()
1339 | ((_, Tprim (Nast.Tatom _ | Nast.Tint | Nast.Tstring)), Nast.Tarraykey)
1341 valid ()
1342 | ((_, Tpu (_, _)), Nast.Tarraykey) -> valid ()
1343 | ((_, Tprim prim_sub), _) when Aast.equal_tprim prim_sub prim_ty ->
1344 valid ()
1345 | ((_, Toption arg_ty_sub), Nast.Tnull) ->
1346 simplify_subtype ~subtype_env ~this_ty arg_ty_sub ty_super env
1347 | (_, _) -> default_subtype env))
1348 | (_, Tobject) ->
1349 (match ety_sub with
1350 | ConstraintType _ -> default_subtype env
1351 (* Any class type is a subtype of object *)
1352 | LoclType lty ->
1353 (match get_node lty with
1354 | Tobject
1355 | Tclass _ ->
1356 valid ()
1357 | _ -> default_subtype env))
1358 | (r_super, Tany _) ->
1359 (match ety_sub with
1360 | ConstraintType cty ->
1361 begin
1362 match deref_constraint_type cty with
1363 | (_, (TCunion _ | TCintersection _)) -> default_subtype env
1364 | _ -> valid ()
1366 | LoclType ty_sub ->
1367 (match deref ty_sub with
1368 | (_, Tany _) -> valid ()
1369 | (_, (Tunion _ | Tintersection _ | Tvar _)) -> default_subtype env
1370 | _ when subtype_env.no_top_bottom -> default ()
1371 (* If ty_sub contains other types, e.g. C<T>, make this a subtype assertion on
1372 those inner types and `any`. For example transform the assertion
1373 C<D> <: Tany
1374 into
1375 C<D> <: C<Tany>
1376 which might become
1377 D <: Tany
1378 if say C is covariant.
1380 | _ ->
1381 let ty_super = anyfy env r_super ty_sub in
1382 simplify_subtype ~subtype_env ~this_ty ty_sub ty_super env))
1383 | (_, Tpu (base_super, (_, enum_super))) ->
1384 (match ety_sub with
1385 | ConstraintType _ -> default_subtype env
1386 | LoclType lty ->
1387 (match deref lty with
1388 (* TODO: document contravariance *)
1389 | (_, Tpu (base_sub, (_, enum_sub)))
1390 when String.equal enum_sub enum_super ->
1391 simplify_subtype ~subtype_env ~this_ty base_super base_sub env
1392 (* Atom vs Tpu: check for membership *)
1393 | (_, Tprim (Aast_defs.Tatom atom))
1394 when Option.is_some
1395 @@ snd
1396 @@ TUtils.class_get_pu_member env base_super enum_super atom ->
1397 valid ()
1398 | _ -> default_subtype env))
1399 | (_, Tpu_type_access (msuper, nsuper)) ->
1400 (match ety_sub with
1401 | ConstraintType _ -> default_subtype env
1402 | LoclType ty_sub ->
1403 (match get_node ty_sub with
1404 | Tpu_type_access (msub, nsub) ->
1406 String.equal (snd nsub) (snd nsuper)
1407 && String.equal (snd msub) (snd msuper)
1408 then
1409 valid_env env
1410 else
1411 (* It's not 100% clear if we should use invalid_env directly or
1412 * not. All my attempts a building an error here is always
1413 * caught beforehand *)
1414 default_subtype env
1415 | Tunion _
1416 | Tvar _
1417 | Tintersection _ ->
1418 default_subtype env
1419 | _ ->
1420 (* TODO: check if err is still needed *)
1421 let err () =
1422 let reason = get_reason ty_sub in
1423 if Typing_utils.is_any env ty_sub then
1425 else
1426 Errors.pu_typing_not_supported (Reason.to_pos reason)
1428 invalid_env_with env err))
1429 | (r_super, Tfun ft_super) ->
1430 (match ety_sub with
1431 | ConstraintType _ -> default_subtype env
1432 | LoclType lty ->
1433 (match deref lty with
1434 | (r_sub, Tfun ft_sub) ->
1435 simplify_subtype_funs
1436 ~subtype_env
1437 ~check_return:true
1438 r_sub
1439 ft_sub
1440 r_super
1441 ft_super
1443 | _ -> default_subtype env))
1444 | (_, Ttuple tyl_super) ->
1445 (match ety_sub with
1446 | ConstraintType _ -> default_subtype env
1447 (* (t1,...,tn) <: (u1,...,un) iff t1<:u1, ... , tn <: un *)
1448 | LoclType lty ->
1449 (match get_node lty with
1450 | Ttuple tyl_sub
1451 when Int.equal (List.length tyl_super) (List.length tyl_sub) ->
1452 wfold_left2
1453 (fun res ty_sub ty_super ->
1454 res &&& simplify_subtype ~subtype_env ty_sub ty_super)
1455 (env, TL.valid)
1456 tyl_sub
1457 tyl_super
1458 | _ -> default_subtype env))
1459 | (r_super, Tshape (shape_kind_super, fdm_super)) ->
1461 * shape_field_type A <: shape_field_type B iff:
1462 * 1. A is no more optional than B
1463 * 2. A's type <: B.type
1465 let simplify_subtype_shape_field
1466 r_sub name res (sft_sub, explicit_sub) (sft_super, _) =
1467 match (sft_sub.sft_optional, sft_super.sft_optional) with
1468 | (_, true)
1469 | (false, false) ->
1471 &&& simplify_subtype
1472 ~subtype_env
1473 ~this_ty
1474 sft_sub.sft_ty
1475 sft_super.sft_ty
1476 | (true, false) ->
1478 |> with_error (fun () ->
1479 let printable_name =
1480 TUtils.get_printable_shape_field_name name
1482 if explicit_sub then
1483 Errors.required_field_is_optional
1484 (Reason.to_pos r_sub)
1485 (Reason.to_pos r_super)
1486 printable_name
1487 subtype_env.on_error
1488 else
1489 Errors.missing_field
1490 (Reason.to_pos r_sub)
1491 (Reason.to_pos r_super)
1492 printable_name
1493 subtype_env.on_error)
1495 let lookup_shape_field_type name r shape_kind fdm =
1496 match ShapeMap.find_opt name fdm with
1497 | Some sft -> (sft, true)
1498 | None ->
1499 let printable_name = TUtils.get_printable_shape_field_name name in
1500 let sft_ty =
1501 match shape_kind with
1502 | Closed_shape ->
1503 MakeType.nothing
1504 (Reason.Rmissing_required_field (Reason.to_pos r, printable_name))
1505 | Open_shape ->
1506 MakeType.mixed
1507 (Reason.Rmissing_optional_field (Reason.to_pos r, printable_name))
1509 ({ sft_ty; sft_optional = true }, false)
1511 (match ety_sub with
1512 | ConstraintType _ -> default_subtype env
1513 | LoclType lty ->
1514 (match deref lty with
1515 | (r_sub, Tshape (Open_shape, _))
1516 when equal_shape_kind Closed_shape shape_kind_super ->
1517 invalid_with (fun () ->
1518 Errors.shape_fields_unknown
1519 (Reason.to_pos r_sub)
1520 (Reason.to_pos r_super)
1521 subtype_env.on_error)
1522 | (r_sub, Tshape (shape_kind_sub, fdm_sub)) ->
1523 ShapeSet.fold
1524 (fun name res ->
1525 simplify_subtype_shape_field
1526 r_sub
1527 name
1529 (lookup_shape_field_type name r_sub shape_kind_sub fdm_sub)
1530 (lookup_shape_field_type
1531 name
1532 r_super
1533 shape_kind_super
1534 fdm_super))
1535 (ShapeSet.of_list (ShapeMap.keys fdm_sub @ ShapeMap.keys fdm_super))
1536 (env, TL.valid)
1537 | _ -> default_subtype env))
1538 | (_, (Tvarray _ | Tdarray _ | Tvarray_or_darray _)) ->
1539 (match ety_sub with
1540 | ConstraintType _ -> default_subtype env
1541 | LoclType lty ->
1542 (match (get_node lty, get_node ty_super) with
1543 | (Tvarray ty_sub, Tvarray ty_super) ->
1544 simplify_subtype ~subtype_env ~this_ty ty_sub ty_super env
1545 | ( Tvarray_or_darray (tk_sub, tv_sub),
1546 Tvarray_or_darray (tk_super, tv_super) )
1547 | (Tdarray (tk_sub, tv_sub), Tdarray (tk_super, tv_super))
1548 | (Tdarray (tk_sub, tv_sub), Tvarray_or_darray (tk_super, tv_super)) ->
1550 |> simplify_subtype ~subtype_env ~this_ty tk_sub tk_super
1551 &&& simplify_subtype ~subtype_env ~this_ty tv_sub tv_super
1552 | (Tvarray tv_sub, Tvarray_or_darray (tk_super, tv_super)) ->
1553 let pos = get_pos lty in
1554 let tk_sub = MakeType.int (Reason.Ridx_vector pos) in
1556 |> simplify_subtype ~subtype_env ~this_ty tk_sub tk_super
1557 &&& simplify_subtype ~subtype_env ~this_ty tv_sub tv_super
1558 | (Tvarray _, Tdarray _)
1559 | (Tdarray _, Tvarray _)
1560 | (Tvarray_or_darray _, Tdarray _)
1561 | (Tvarray_or_darray _, Tvarray _) ->
1562 invalid ()
1563 | _ -> default_subtype env))
1564 | (_, Tnewtype (name_super, tyl_super, _)) ->
1565 (match ety_sub with
1566 | ConstraintType _ -> default_subtype env
1567 | LoclType lty ->
1568 (match deref lty with
1569 | (_, Tclass ((_, name_sub), _, _)) ->
1570 if String.equal name_sub name_super && Env.is_enum env name_super then
1571 valid ()
1572 else
1573 default_subtype env
1574 | (_, Tnewtype (name_sub, tyl_sub, _))
1575 when String.equal name_sub name_super ->
1576 if List.is_empty tyl_sub then
1577 valid ()
1578 else if Env.is_enum env name_super && Env.is_enum env name_sub then
1579 valid ()
1580 else
1581 let td = Env.get_typedef env name_super in
1582 begin
1583 match td with
1584 | Some { td_tparams; _ } ->
1585 let variance_reifiedl =
1586 List.map td_tparams (fun t -> (t.tp_variance, t.tp_reified))
1588 simplify_subtype_variance
1589 ~subtype_env
1590 name_sub
1591 variance_reifiedl
1592 tyl_sub
1593 tyl_super
1595 | None -> invalid ()
1597 | _ -> default_subtype env))
1598 | (r_super, Tclass (((_, class_name) as x_super), exact_super, tyl_super))
1600 (match ety_sub with
1601 | ConstraintType _ -> default_subtype env
1602 | LoclType ty_sub ->
1603 (match deref ty_sub with
1604 | (_, Tnewtype (enum_name, _, _))
1605 when String.equal enum_name class_name
1606 && equal_exact exact_super Nonexact
1607 && Env.is_enum env enum_name ->
1608 valid ()
1609 | (_, Tnewtype (cid, _, _))
1610 when String.equal class_name SN.Classes.cHH_BuiltinEnum
1611 && Env.is_enum env cid ->
1612 (match tyl_super with
1613 | [ty_super'] ->
1614 env |> simplify_subtype ~subtype_env ~this_ty ty_sub ty_super'
1615 | _ -> default_subtype env)
1616 | (_, Tnewtype (enum_name, _, _))
1617 when (String.equal enum_name class_name && Env.is_enum env enum_name)
1618 || String.equal class_name SN.Classes.cXHPChild ->
1619 valid ()
1620 | ( _,
1621 ( Tvarray _ | Tdarray _ | Tvarray_or_darray _
1622 | Tprim Nast.(Tstring | Tarraykey | Tint | Tfloat | Tnum) ) )
1623 when String.equal class_name SN.Classes.cXHPChild
1624 && equal_exact exact_super Nonexact ->
1625 valid ()
1626 | (_, Tprim Nast.Tstring)
1627 when String.equal class_name SN.Classes.cStringish
1628 && equal_exact exact_super Nonexact ->
1629 valid ()
1630 (* Match what's done in unify for non-strict code *)
1631 | (_, Tobject)
1632 when not @@ Partial.should_check_error (Env.get_mode env) 4110 ->
1633 valid ()
1634 | (r_sub, Tclass (x_sub, exact_sub, tyl_sub)) ->
1635 let (cid_super, cid_sub) = (snd x_super, snd x_sub) in
1636 let exact_match =
1637 match (exact_sub, exact_super) with
1638 | (Nonexact, Exact) -> false
1639 | (_, _) -> true
1641 if String.equal cid_super cid_sub then
1642 if List.is_empty tyl_sub && List.is_empty tyl_super && exact_match
1643 then
1644 valid ()
1645 else
1646 (* This is side-effecting as it registers a dependency *)
1647 let class_def_sub = Env.get_class env cid_sub in
1648 (* If class is final then exactness is superfluous *)
1649 let is_final =
1650 match class_def_sub with
1651 | Some tc -> Cls.final tc
1652 | None -> false
1654 if not (exact_match || is_final) then
1655 invalid ()
1656 else
1657 (* We handle the case where a generic A<T> is used as A *)
1658 let tyl_super =
1660 List.is_empty tyl_super
1661 && not (Partial.should_check_error (Env.get_mode env) 4101)
1662 then
1663 List.map tyl_sub (fun _ ->
1664 mk (r_super, Typing_defs.make_tany ()))
1665 else
1666 tyl_super
1668 let tyl_sub =
1670 List.is_empty tyl_sub
1671 && not (Partial.should_check_error (Env.get_mode env) 4101)
1672 then
1673 List.map tyl_super (fun _ ->
1674 mk (r_super, Typing_defs.make_tany ()))
1675 else
1676 tyl_sub
1678 if Int.( <> ) (List.length tyl_sub) (List.length tyl_super) then
1679 let n_sub = String_utils.soi (List.length tyl_sub) in
1680 let n_super = String_utils.soi (List.length tyl_super) in
1681 invalid_with (fun () ->
1682 Errors.type_arity_mismatch
1683 (fst x_super)
1684 n_super
1685 (fst x_sub)
1686 n_sub
1687 subtype_env.on_error)
1688 else
1689 let variance_reifiedl =
1690 match class_def_sub with
1691 | None ->
1692 List.map tyl_sub (fun _ ->
1693 (Ast_defs.Invariant, Aast.Erased))
1694 | Some class_sub ->
1695 List.map (Cls.tparams class_sub) (fun t ->
1696 (t.tp_variance, t.tp_reified))
1698 (* C<t1, .., tn> <: C<u1, .., un> iff
1699 * t1 <:v1> u1 /\ ... /\ tn <:vn> un
1700 * where vi is the variance of the i'th generic parameter of C,
1701 * and <:v denotes the appropriate direction of subtyping for variance v
1703 simplify_subtype_variance
1704 ~subtype_env
1705 cid_sub
1706 variance_reifiedl
1707 tyl_sub
1708 tyl_super
1710 else if not exact_match then
1711 invalid ()
1712 else
1713 let class_def_sub = Env.get_class env cid_sub in
1714 (match class_def_sub with
1715 | None ->
1716 (* This should have been caught already in the naming phase *)
1717 valid ()
1718 | Some class_sub ->
1719 (* We handle the case where a generic A<T> is used as A *)
1720 let tyl_sub =
1722 List.is_empty tyl_sub
1723 && not (Partial.should_check_error (Env.get_mode env) 4029)
1724 then
1725 List.map (Cls.tparams class_sub) (fun _ ->
1726 mk (r_sub, Typing_defs.make_tany ()))
1727 else
1728 tyl_sub
1732 (Int.equal
1733 (List.length (Cls.tparams class_sub))
1734 (List.length tyl_sub))
1735 then
1736 invalid_with (fun () ->
1737 Errors.expected_tparam
1738 ~definition_pos:(Cls.pos class_sub)
1739 ~use_pos:(Reason.to_pos r_sub)
1740 (List.length (Cls.tparams class_sub))
1741 (Some subtype_env.on_error))
1742 else
1743 let ety_env =
1745 type_expansions = [];
1746 substs = Subst.make_locl (Cls.tparams class_sub) tyl_sub;
1747 (* TODO: do we need this? *)
1748 this_ty = Option.value this_ty ~default:ty_sub;
1749 from_class = None;
1750 quiet = true;
1751 on_error = subtype_env.on_error;
1754 let up_obj = Cls.get_ancestor class_sub cid_super in
1755 (match up_obj with
1756 | Some up_obj ->
1757 let (env, up_obj) = Phase.localize ~ety_env env up_obj in
1758 simplify_subtype ~subtype_env ~this_ty up_obj ty_super env
1759 | None ->
1761 Ast_defs.(equal_class_kind (Cls.kind class_sub) Ctrait)
1762 || Ast_defs.(
1763 equal_class_kind (Cls.kind class_sub) Cinterface)
1764 then
1765 let rec try_upper_bounds_on_this up_objs env =
1766 match up_objs with
1767 | [] ->
1768 (* It's crucial that we don't lose updates to global_tpenv in env that were
1769 * introduced by PHase.localize. TODO: avoid this requirement *)
1770 invalid_env env
1771 | ub_obj_typ :: up_objs ->
1772 (* a trait is never the runtime type, but it can be used
1773 * as a constraint if it has requirements or where constraints
1774 * for its using classes *)
1775 let (env, ub_obj_typ) =
1776 Phase.localize ~ety_env env ub_obj_typ
1779 |> simplify_subtype
1780 ~subtype_env
1781 ~this_ty
1782 (mk (r_sub, get_node ub_obj_typ))
1783 ty_super
1784 ||| try_upper_bounds_on_this up_objs
1786 try_upper_bounds_on_this
1787 (Cls.upper_bounds_on_this class_sub)
1789 else
1790 invalid ()))
1791 | (r_sub, (Tvarray tv | Tdarray (_, tv) | Tvarray_or_darray (_, tv))) ->
1792 (match (exact_super, tyl_super) with
1793 | (Nonexact, [tv_super])
1794 when String.equal class_name SN.Collections.cTraversable
1795 || String.equal class_name SN.Rx.cTraversable
1796 || String.equal class_name SN.Collections.cContainer ->
1797 (* vec<tv> <: Traversable<tv_super>
1798 * iff tv <: tv_super
1799 * Likewise for vec<tv> <: Container<tv_super>
1800 * and map<_,tv> <: Traversable<tv_super>
1801 * and map<_,tv> <: Container<tv_super>
1803 simplify_subtype ~subtype_env ~this_ty tv tv_super env
1804 | (Nonexact, [tk_super; tv_super])
1805 when String.equal class_name SN.Collections.cKeyedTraversable
1806 || String.equal class_name SN.Rx.cKeyedTraversable
1807 || String.equal class_name SN.Collections.cKeyedContainer ->
1808 (match get_node ty_sub with
1809 | Tvarray _ ->
1811 |> simplify_subtype
1812 ~subtype_env
1813 ~this_ty
1814 (MakeType.int r_sub)
1815 tk_super
1816 &&& simplify_subtype ~subtype_env ~this_ty tv tv_super
1817 | Tvarray_or_darray (tk, _)
1818 | Tdarray (tk, _) ->
1820 |> simplify_subtype ~subtype_env ~this_ty tk tk_super
1821 &&& simplify_subtype ~subtype_env ~this_ty tv tv_super
1822 | _ -> default_subtype env)
1823 | (Nonexact, [])
1824 when String.equal class_name SN.Collections.cKeyedTraversable
1825 || String.equal class_name SN.Rx.cKeyedTraversable
1826 || String.equal class_name SN.Collections.cKeyedContainer ->
1827 (* All arrays are subtypes of the untyped KeyedContainer / Traversables *)
1828 valid ()
1829 | (_, _) -> default_subtype env)
1830 | _ -> default_subtype env)))
1832 and simplify_subtype_variance
1833 ~(subtype_env : subtype_env)
1834 (cid : string)
1835 (variance_reifiedl : (Ast_defs.variance * Aast.reify_kind) list)
1836 (children_tyl : locl_ty list)
1837 (super_tyl : locl_ty list) : env -> env * TL.subtype_prop =
1838 fun env ->
1839 let simplify_subtype reify_kind =
1840 (* When doing coercions we treat dynamic as a bottom type. This is generally
1841 correct, except for the case when the generic isn't erased. When a generic is
1842 reified it is enforced as if it is it's own separate class in the runtime. i.e.
1843 In the code:
1845 class Box<reify T> {}
1846 function box_int(): Box<int> { return new Box<~int>(); }
1848 If is enforced like:
1849 class Box<reify T> {}
1850 class Box_int extends Box<int> {}
1851 class Box_like_int extends Box<~int> {}
1853 function box_int(): Box_int { return new Box_like_int(); }
1855 Thus we cannot push the like type to the outside of generic like we can
1856 we erased generics.
1859 let subtype_env =
1860 if not Aast.(equal_reify_kind reify_kind Erased) then
1861 { subtype_env with treat_dynamic_as_bottom = false }
1862 else
1863 subtype_env
1865 simplify_subtype ~subtype_env ~this_ty:None
1867 let simplify_subtype_variance = simplify_subtype_variance ~subtype_env in
1868 match (variance_reifiedl, children_tyl, super_tyl) with
1869 | ([], _, _)
1870 | (_, [], _)
1871 | (_, _, []) ->
1872 valid env
1873 | ( (variance, reify_kind) :: variance_reifiedl,
1874 child :: childrenl,
1875 super :: superl ) ->
1876 let simplify_subtype = simplify_subtype reify_kind in
1877 begin
1878 match variance with
1879 | Ast_defs.Covariant -> simplify_subtype child super env
1880 | Ast_defs.Contravariant ->
1881 let super =
1883 ( Reason.Rcontravariant_generic (get_reason super, cid),
1884 get_node super )
1886 simplify_subtype super child env
1887 | Ast_defs.Invariant ->
1888 let super' =
1889 mk (Reason.Rinvariant_generic (get_reason super, cid), get_node super)
1891 env |> simplify_subtype child super' &&& simplify_subtype super' child
1893 &&& simplify_subtype_variance cid variance_reifiedl childrenl superl
1895 and simplify_subtype_params
1896 ~(subtype_env : subtype_env)
1897 ?(is_method : bool = false)
1898 ?(check_params_reactivity = false)
1899 ?(check_params_mutability = false)
1900 (subl : locl_fun_param list)
1901 (superl : locl_fun_param list)
1902 (variadic_sub_ty : locl_possibly_enforced_ty option)
1903 (variadic_super_ty : locl_possibly_enforced_ty option)
1904 env =
1905 let simplify_subtype_possibly_enforced =
1906 simplify_subtype_possibly_enforced ~subtype_env
1908 let simplify_subtype_params = simplify_subtype_params ~subtype_env in
1909 let simplify_subtype_params_with_variadic =
1910 simplify_subtype_params_with_variadic ~subtype_env
1912 let simplify_supertype_params_with_variadic =
1913 simplify_supertype_params_with_variadic ~subtype_env
1915 match (subl, superl) with
1916 (* When either list runs out, we still have to typecheck that
1917 the remaining portion sub/super types with the other's variadic.
1918 For example, if
1919 ChildClass {
1920 public function a(int $x = 0, string ... $args) // superl = [int], super_var = string
1922 overrides
1923 ParentClass {
1924 public function a(string ... $args) // subl = [], sub_var = string
1926 , there should be an error because the first argument will be checked against
1927 int, not string that is, ChildClass::a("hello") would crash,
1928 but ParentClass::a("hello") wouldn't.
1930 Similarly, if the other list is longer, aka
1931 ChildClass extends ParentClass {
1932 public function a(mixed ... $args) // superl = [], super_var = mixed
1934 overrides
1935 ParentClass {
1936 //subl = [string], sub_var = string
1937 public function a(string $x = 0, string ... $args)
1939 It should also check that string is a subtype of mixed.
1941 | ([], _) ->
1942 (match variadic_super_ty with
1943 | None -> valid env
1944 | Some ty -> simplify_supertype_params_with_variadic superl ty env)
1945 | (_, []) ->
1946 (match variadic_sub_ty with
1947 | None -> valid env
1948 | Some ty -> simplify_subtype_params_with_variadic subl ty env)
1949 | (sub :: subl, super :: superl) ->
1950 ( env
1951 |> begin
1952 if check_params_reactivity then
1953 simplify_subtype_fun_params_reactivity ~subtype_env sub super
1954 else
1955 valid
1958 if check_params_mutability then
1959 check_mutability
1960 ~is_receiver:false
1961 ~subtype_env
1962 sub.fp_pos
1963 (get_fp_mutability sub)
1964 super.fp_pos
1965 (get_fp_mutability super)
1966 else
1967 valid )
1968 &&& fun env ->
1969 let { fp_type = ty_sub; _ } = sub in
1970 let { fp_type = ty_super; _ } = super in
1971 (* Check that the calling conventions of the params are compatible. *)
1973 |> simplify_param_modes ~subtype_env sub super
1974 &&& simplify_param_accept_disposable ~subtype_env sub super
1975 &&& begin
1976 fun env ->
1977 match (get_fp_mode sub, get_fp_mode super) with
1978 | (FPinout, FPinout) ->
1979 (* Inout parameters are invariant wrt subtyping for function types. *)
1981 |> simplify_subtype_possibly_enforced ty_super ty_sub
1982 &&& simplify_subtype_possibly_enforced ty_sub ty_super
1983 | _ -> env |> simplify_subtype_possibly_enforced ty_sub ty_super
1985 &&& simplify_subtype_params
1986 ~is_method
1987 subl
1988 superl
1989 variadic_sub_ty
1990 variadic_super_ty
1992 and simplify_subtype_params_with_variadic
1993 ~(subtype_env : subtype_env)
1994 (subl : locl_fun_param list)
1995 (variadic_ty : locl_possibly_enforced_ty)
1996 env =
1997 let simplify_subtype_possibly_enforced =
1998 simplify_subtype_possibly_enforced ~subtype_env
2000 let simplify_subtype_params_with_variadic =
2001 simplify_subtype_params_with_variadic ~subtype_env
2003 match subl with
2004 | [] -> valid env
2005 | { fp_type = sub; _ } :: subl ->
2007 |> simplify_subtype_possibly_enforced sub variadic_ty
2008 &&& simplify_subtype_params_with_variadic subl variadic_ty
2010 and simplify_supertype_params_with_variadic
2011 ~(subtype_env : subtype_env)
2012 (superl : locl_fun_param list)
2013 (variadic_ty : locl_possibly_enforced_ty)
2014 env =
2015 let simplify_subtype_possibly_enforced =
2016 simplify_subtype_possibly_enforced ~subtype_env
2018 let simplify_supertype_params_with_variadic =
2019 simplify_supertype_params_with_variadic ~subtype_env
2021 match superl with
2022 | [] -> valid env
2023 | { fp_type = super; _ } :: superl ->
2025 |> simplify_subtype_possibly_enforced variadic_ty super
2026 &&& simplify_supertype_params_with_variadic superl variadic_ty
2028 and simplify_subtype_reactivity
2029 ~subtype_env
2030 ?(extra_info : reactivity_extra_info option)
2031 ?(is_call_site = false)
2032 p_sub
2033 (r_sub : reactivity)
2034 p_super
2035 (r_super : reactivity)
2036 (env : env) : env * TL.subtype_prop =
2037 let fail () =
2038 let msg_super =
2039 "This function is " ^ TUtils.reactivity_to_string env r_super ^ "."
2041 let msg_sub =
2042 "This function is " ^ TUtils.reactivity_to_string env r_sub ^ "."
2044 subtype_env.on_error [(p_super, msg_super); (p_sub, msg_sub)]
2046 let ( ||| ) = ( ||| ) ~fail in
2047 let invalid () = invalid ~fail env in
2048 let valid () = valid env in
2049 let maybe_localize t =
2050 match t with
2051 | DeclTy t ->
2052 let ety_env = Phase.env_with_self env in
2053 let (_, t) = Phase.localize ~ety_env env t in
2055 | LoclTy t -> t
2057 let class_ty =
2058 Option.bind extra_info (fun { class_ty = cls; _ } ->
2059 Option.map cls ~f:maybe_localize)
2061 (* for method declarations check if condition type for r_super includes
2062 reactive method with a matching name. If yes - then it will act as a guarantee
2063 that derived class will have to redefine the method with a shape required
2064 by condition type (reactivity of redefined method must be subtype of reactivity
2065 of method in interface) *)
2066 let check_condition_type_has_matching_reactive_method env =
2067 (* function type TSub of method M with arbitrary reactivity in derive class
2068 can be subtype of conditionally reactive function type TSuper of method M
2069 defined in base class when condition type has reactive method M.
2070 interface Rx {
2071 <<__Rx>>
2072 public function f(): int;
2074 class A {
2075 <<__RxIfImplements(Rx::class)>>
2076 public function f(): int { ... }
2078 class B extends A {
2079 public function f(): int { ... }
2081 This should be OK because:
2082 - B does not implement Rx (B::f is not compatible with Rx::f) which means
2083 that calling ($b : B)->f() will not be treated as reactive
2084 - if one of subclasses of B will decide to implement B - they will be forced
2085 to redeclare f which now will shadow B::f. Note that B::f will still be
2086 accessible as parent::f() but will be treated as non-reactive call.
2088 match (r_super, extra_info) with
2089 | ( ( Pure (Some condition_type_super)
2090 | Reactive (Some condition_type_super)
2091 | Shallow (Some condition_type_super)
2092 | Local (Some condition_type_super) ),
2093 Some { method_info = Some (method_name, is_static); _ } ) ->
2094 let m =
2095 ConditionTypes.try_get_method_from_condition_type
2097 condition_type_super
2098 is_static
2099 method_name
2101 begin
2102 (* check that reactivity of interface method (effectively a promised
2103 reactivity of a method in derived class) is a subtype of r_super.
2104 NOTE: we check only for unconditional reactivity since conditional
2105 version does not seems to yield a lot and will requre implementing
2106 cycle detection for condition types *)
2107 match m with
2108 | Some { ce_type = (lazy ty); _ } ->
2109 begin
2110 match get_node ty with
2111 | Tfun
2113 ft_reactive =
2114 (Pure None | Reactive None | Shallow None | Local None) as
2117 } ->
2118 let extra_info =
2120 empty_extra_info with
2121 parent_class_ty = Some (DeclTy condition_type_super);
2124 simplify_subtype_reactivity
2125 ~subtype_env
2126 ~extra_info
2127 p_sub
2129 p_super
2130 r_super
2132 | _ -> invalid ()
2134 | _ -> invalid ()
2136 | _ -> invalid ()
2138 match (r_sub, r_super) with
2139 (* anything is a subtype of nonreactive functions *)
2140 | (_, Nonreactive) -> valid ()
2141 (* to compare two maybe reactive values we need to unwrap them *)
2142 | (MaybeReactive sub, MaybeReactive super) ->
2143 simplify_subtype_reactivity
2144 ~subtype_env
2145 ?extra_info
2146 ~is_call_site
2147 p_sub
2149 p_super
2150 super
2152 (* for explicit checks at callsites implicitly unwrap maybereactive value:
2153 function f(<<__AtMostRxAsFunc>> F $f)
2154 f(<<__RxLocal>> () ==> {... })
2155 here parameter will be maybereactive and argument - rxlocal
2157 | (sub, MaybeReactive super) when is_call_site ->
2158 simplify_subtype_reactivity
2159 ~subtype_env
2160 ?extra_info
2161 ~is_call_site
2162 p_sub
2164 p_super
2165 super
2167 (* if is_call_site is falst ignore maybereactive flavors.
2168 This usually happens during subtype checks for arguments and when target
2169 function is conditionally reactive we'll do the proper check
2170 in typing_reactivity.check_call. *)
2171 | (_, MaybeReactive _) when not is_call_site -> valid ()
2172 (* ok:
2173 class A { function f((function(): int) $f) {} }
2174 class B extends A {
2175 <<__Rx>>
2176 function f(<<__AtMostRxAsFunc>> (function(): int) $f);
2178 reactivity for arguments is checked contravariantly *)
2179 | (_, RxVar None)
2180 (* ok:
2181 <<__Rx>>
2182 function f(<<__AtMostRxAsFunc>> (function(): int) $f) { return $f() } *)
2183 | (RxVar None, RxVar _) ->
2184 valid ()
2185 | (RxVar (Some sub), RxVar (Some super))
2186 | (sub, RxVar (Some super)) ->
2187 simplify_subtype_reactivity
2188 ~subtype_env
2189 ?extra_info
2190 ~is_call_site
2191 p_sub
2193 p_super
2194 super
2196 | (RxVar _, _) -> invalid ()
2197 | ( (Local cond_sub | Shallow cond_sub | Reactive cond_sub | Pure cond_sub),
2198 Local cond_super )
2199 | ((Shallow cond_sub | Reactive cond_sub | Pure cond_sub), Shallow cond_super)
2200 | ((Reactive cond_sub | Pure cond_sub), Reactive cond_super)
2201 | (Pure cond_sub, Pure cond_super) ->
2203 |> simplify_subtype_param_rx_if_impl
2204 ~subtype_env
2205 ~is_param:false
2206 p_sub
2207 cond_sub
2208 class_ty
2209 p_super
2210 cond_super
2211 ||| check_condition_type_has_matching_reactive_method
2212 (* call_site specific cases *)
2213 (* shallow can call into local *)
2214 | (Local cond_sub, Shallow cond_super) when is_call_site ->
2215 simplify_subtype_param_rx_if_impl
2216 ~subtype_env
2217 ~is_param:false
2218 p_sub
2219 cond_sub
2220 class_ty
2221 p_super
2222 cond_super
2224 (* local can call into non-reactive *)
2225 | (Nonreactive, Local _) when is_call_site -> valid ()
2226 | _ -> check_condition_type_has_matching_reactive_method env
2228 and should_check_fun_params_reactivity (ft_super : locl_fun_type) =
2229 not (equal_reactivity ft_super.ft_reactive Nonreactive)
2231 (* checks condition described by OnlyRxIfImpl condition on parameter is met *)
2232 and simplify_subtype_param_rx_if_impl
2233 ~subtype_env
2234 ~is_param
2235 p_sub
2236 (cond_type_sub : decl_ty option)
2237 (declared_type_sub : locl_ty option)
2238 p_super
2239 (cond_type_super : decl_ty option)
2240 (env : env) : env * TL.subtype_prop =
2241 let cond_type_sub =
2242 Option.map cond_type_sub ~f:(ConditionTypes.localize_condition_type env)
2244 let cond_type_super =
2245 Option.map cond_type_super ~f:(ConditionTypes.localize_condition_type env)
2247 let invalid () =
2248 ( env,
2249 TL.invalid ~fail:(fun () ->
2250 Errors.rx_parameter_condition_mismatch
2251 SN.UserAttributes.uaOnlyRxIfImpl
2252 p_sub
2253 p_super
2254 subtype_env.on_error) )
2256 match (cond_type_sub, cond_type_super) with
2257 (* no condition types - do nothing *)
2258 | (None, None) -> valid env
2259 (* condition type is specified only for super - ok for receiver case (is_param is false)
2260 abstract class A {
2261 <<__RxLocal, __OnlyRxIfImpl(Rx1::class)>>
2262 public abstract function condlocalrx(): int;
2264 abstract class B extends A {
2265 // ok to override cond local with local (if condition is not met - method
2266 // in base class is non-reactive )
2267 <<__Override, __RxLocal>>
2268 public function condlocalrx(): int {
2269 return 1;
2272 for parameters we need to verify that declared type of sub is a subtype of
2273 conditional type for super. Here is an example where this is violated:
2275 interface A {}
2276 interface RxA {}
2278 class C1 {
2279 <<__Rx>>
2280 public function f(A $a): void {
2284 class C2 extends C1 {
2285 // ERROR: invariant f body is reactive iff $a instanceof RxA can be violated
2286 <<__Rx, __AtMostRxAsArgs>>
2287 public function f(<<__OnlyRxIfImpl(RxA::class)>>A $a): void {
2290 here declared type of sub is A
2291 and cond type of super is RxA
2293 | (None, Some _) when not is_param -> valid env
2294 | (None, Some cond_type_super) ->
2295 begin
2296 match declared_type_sub with
2297 | None -> invalid ()
2298 | Some declared_type_sub ->
2299 simplify_subtype ~subtype_env declared_type_sub cond_type_super env
2301 (* condition types are set for both sub and super types: contravariant check
2302 interface A {}
2303 interface B extends A {}
2304 interface C extends B {}
2306 interface I1 {
2307 <<__Rx, __OnlyRxIfImpl(B::class)>>
2308 public function f(): void;
2309 <<__Rx>>
2310 public function g(<<__OnlyRxIfImpl(B::class)>> A $a): void;
2312 interface I2 extends I1 {
2313 // OK since condition in I1::f covers I2::f
2314 <<__Rx, __OnlyRxIfImpl(A::class)>>
2315 public function f(): void;
2316 // OK since condition in I1::g covers I2::g
2317 <<__Rx>>
2318 public function g(<<__OnlyRxIfImpl(A::class)>> A $a): void;
2320 interface I3 extends I1 {
2321 // Error since condition in I1::f is less strict that in I3::f
2322 <<__Rx, __OnlyRxIfImpl(C::class)>>
2323 public function f(): void;
2324 // Error since condition in I1::g is less strict that in I3::g
2325 <<__Rx>>
2326 public function g(<<__OnlyRxIfImpl(C::class)>> A $a): void;
2329 | (Some cond_type_sub, Some cond_type_super) ->
2330 if is_param then
2331 simplify_subtype ~subtype_env cond_type_sub cond_type_super env
2332 else
2333 simplify_subtype ~subtype_env cond_type_super cond_type_sub env
2334 (* condition type is set for super type, check if declared type of
2335 subtype is a subtype of condition type
2336 interface Rx {
2337 <<__Rx>>
2338 public function f(int $a): void;
2340 class A<T> {
2341 <<__Rx, __OnlyRxIfImpl(Rx::class)>>
2342 public function f(T $a): void {
2345 // B <: Rx so B::f is completely reactive
2346 class B extends A<int> implements Rx {
2347 } *)
2348 | (Some cond_type_sub, None) ->
2349 if is_param then
2350 valid env
2351 else begin
2352 match declared_type_sub with
2353 | None -> invalid ()
2354 | Some declared_type_sub ->
2355 simplify_subtype ~subtype_env declared_type_sub cond_type_sub env
2358 (* checks reactivity conditions for function parameters *)
2359 and simplify_subtype_fun_params_reactivity
2360 ~subtype_env (p_sub : locl_fun_param) (p_super : locl_fun_param) env =
2361 match (p_sub.fp_rx_annotation, p_super.fp_rx_annotation) with
2362 (* no conditions on parameters - do nothing *)
2363 | (None, None) -> valid env
2364 (* both parameters are conditioned to be rx function - no need to check anything *)
2365 | (Some Param_rx_var, Some Param_rx_var) -> valid env
2366 | (None, Some Param_rx_var) ->
2367 (* parameter is conditionally reactive in supertype and missing condition
2368 in subtype - this is ok only if parameter in subtype is reactive
2369 <<__Rx>>
2370 function super((function(): int) $f);
2371 <<__Rx>>
2372 function sub(<<__AtMostRxAsFunc>> (function(): int) $f);
2373 We check if sub <: super. parameters are checked contravariantly
2374 so we need to verify that
2375 (function(): int) $f <: <<__AtMostRxAsFunc>> (function(): int) $f
2377 Suppose this is legal, then this will be allowed (in pseudo-code)
2379 function sub(<<__AtMostRxAsFunc>> (function(): int) $f) {
2380 $f(); // can call function here since it is conditionally reactive
2382 <<__Rx>>
2383 function g() {
2384 $f: super = sub;
2385 // invoke non-reactive code in reactive context which is bad
2386 $f(() ==> { echo 1; });
2389 It will be safe if parameter in super will be completely reactive,
2390 hence check below *)
2391 let (_, p_sub_type) = Env.expand_type env p_sub.fp_type.et_type in
2392 begin
2393 match get_node p_sub_type with
2394 | Tfun tfun when not (equal_reactivity tfun.ft_reactive Nonreactive) ->
2395 valid env
2396 | Tfun _ ->
2397 ( env,
2398 TL.invalid ~fail:(fun () ->
2399 Errors.rx_parameter_condition_mismatch
2400 SN.UserAttributes.uaAtMostRxAsFunc
2401 p_sub.fp_pos
2402 p_super.fp_pos
2403 subtype_env.on_error) )
2404 (* parameter type is not function - error will be reported in different place *)
2405 | _ -> valid env
2407 | (cond_sub, cond_super) ->
2408 let cond_type_sub =
2409 match cond_sub with
2410 | Some (Param_rx_if_impl t) -> Some t
2411 | _ -> None
2413 let cond_type_super =
2414 match cond_super with
2415 | Some (Param_rx_if_impl t) -> Some t
2416 | _ -> None
2418 let subtype_env =
2420 subtype_env with
2421 on_error =
2422 (fun ?code:_ _ ->
2423 Errors.rx_parameter_condition_mismatch
2424 SN.UserAttributes.uaOnlyRxIfImpl
2425 p_sub.fp_pos
2426 p_super.fp_pos
2427 subtype_env.on_error);
2430 simplify_subtype_param_rx_if_impl
2431 ~subtype_env
2432 ~is_param:true
2433 p_sub.fp_pos
2434 cond_type_sub
2435 (Some p_sub.fp_type.et_type)
2436 p_super.fp_pos
2437 cond_type_super
2440 and simplify_param_modes ~subtype_env param1 param2 env =
2441 let { fp_pos = pos1; _ } = param1 in
2442 let { fp_pos = pos2; _ } = param2 in
2443 match (get_fp_mode param1, get_fp_mode param2) with
2444 | (FPnormal, FPnormal)
2445 | (FPinout, FPinout) ->
2446 valid env
2447 | (FPnormal, FPinout) ->
2448 invalid
2449 ~fail:(fun () -> Errors.inoutness_mismatch pos2 pos1 subtype_env.on_error)
2451 | (FPinout, FPnormal) ->
2452 invalid
2453 ~fail:(fun () -> Errors.inoutness_mismatch pos1 pos2 subtype_env.on_error)
2456 and simplify_param_accept_disposable ~subtype_env param1 param2 env =
2457 let { fp_pos = pos1; _ } = param1 in
2458 let { fp_pos = pos2; _ } = param2 in
2459 match (get_fp_accept_disposable param1, get_fp_accept_disposable param2) with
2460 | (true, false) ->
2461 invalid
2462 ~fail:(fun () ->
2463 Errors.accept_disposable_invariant pos1 pos2 subtype_env.on_error)
2465 | (false, true) ->
2466 invalid
2467 ~fail:(fun () ->
2468 Errors.accept_disposable_invariant pos2 pos1 subtype_env.on_error)
2470 | (_, _) -> valid env
2472 (* Helper function for subtyping on function types: performs all checks that
2473 * don't involve actual types:
2474 * <<__ReturnDisposable>> attribute
2475 * <<__MutableReturn>> attribute
2476 * <<__Rx>> attribute
2477 * <<__Mutable>> attribute
2478 * whether or not the function is a coroutine
2479 * variadic arity
2481 and simplify_subtype_funs_attributes
2482 ~subtype_env
2483 ?(extra_info : reactivity_extra_info option)
2484 (r_sub : Reason.t)
2485 (ft_sub : locl_fun_type)
2486 (r_super : Reason.t)
2487 (ft_super : locl_fun_type)
2488 env =
2489 let p_sub = Reason.to_pos r_sub in
2490 let p_super = Reason.to_pos r_super in
2491 let on_error ?code:_ _ =
2492 Errors.fun_reactivity_mismatch
2493 p_super
2494 (TUtils.reactivity_to_string env ft_super.ft_reactive)
2495 p_sub
2496 (TUtils.reactivity_to_string env ft_sub.ft_reactive)
2497 subtype_env.on_error
2499 simplify_subtype_reactivity
2500 ~subtype_env:{ subtype_env with on_error }
2501 ?extra_info
2502 p_sub
2503 ft_sub.ft_reactive
2504 p_super
2505 ft_super.ft_reactive
2507 |> check_with
2508 (Bool.equal (get_ft_is_coroutine ft_sub) (get_ft_is_coroutine ft_super))
2509 (fun () ->
2510 Errors.coroutinness_mismatch
2511 (get_ft_is_coroutine ft_super)
2512 p_super
2513 p_sub
2514 subtype_env.on_error)
2515 |> check_with
2516 (Bool.equal
2517 (get_ft_return_disposable ft_sub)
2518 (get_ft_return_disposable ft_super))
2519 (fun () ->
2520 Errors.return_disposable_mismatch
2521 (get_ft_return_disposable ft_super)
2522 p_super
2523 p_sub
2524 subtype_env.on_error)
2525 |> (* it is ok for subclass to return mutably owned value and treat it as immutable -
2526 the fact that value is mutably owned guarantees it has only single reference so
2527 as a result this single reference will be immutable. However if super type
2528 returns mutable value and subtype yields immutable value - this is not safe.
2529 NOTE: error is not reported if child is non-reactive since it does not have
2530 immutability-by-default behavior *)
2531 check_with
2532 ( Bool.equal
2533 (get_ft_returns_mutable ft_sub)
2534 (get_ft_returns_mutable ft_super)
2535 || (not (get_ft_returns_mutable ft_super))
2536 || equal_reactivity ft_sub.ft_reactive Nonreactive )
2537 (fun () ->
2538 Errors.mutable_return_result_mismatch
2539 (get_ft_returns_mutable ft_super)
2540 p_super
2541 p_sub
2542 subtype_env.on_error)
2543 |> check_with
2544 ( equal_reactivity ft_super.ft_reactive Nonreactive
2545 || get_ft_returns_void_to_rx ft_super
2546 || not (get_ft_returns_void_to_rx ft_sub) )
2547 (fun () ->
2548 (* __ReturnsVoidToRx can be omitted on subtype, in this case using subtype
2549 via reference to supertype in rx context will be ok since result will be
2550 discarded. The opposite is not true:
2551 class A {
2552 <<__Rx, __Mutable>>
2553 public function f(): A { return new A(); }
2555 class B extends A {
2556 <<__Rx, __Mutable, __ReturnsVoidToRx>>
2557 public function f(): A { return $this; }
2560 <<__Rx, __MutableReturn>>
2561 function f(): A { return new B(); }
2562 $a = HH\Rx\mutable(f());
2563 $a1 = $a->f(); // immutable alias to mutable reference *)
2564 Errors.return_void_to_rx_mismatch
2565 ~pos1_has_attribute:true
2566 p_sub
2567 p_super
2568 subtype_env.on_error)
2570 (* check mutability only for reactive functions *)
2571 let check_params_mutability =
2572 (not (equal_reactivity ft_super.ft_reactive Nonreactive))
2573 && not (equal_reactivity ft_sub.ft_reactive Nonreactive)
2575 fun (env, prop) ->
2576 ( if check_params_mutability (* check mutability of receivers *) then
2577 (env, prop)
2578 &&& check_mutability
2579 ~is_receiver:true
2580 ~subtype_env
2581 p_super
2582 (get_ft_param_mutable ft_super)
2583 p_sub
2584 (get_ft_param_mutable ft_sub)
2585 else
2586 (env, prop) )
2587 |> check_with
2588 (arity_min ft_sub <= arity_min ft_super)
2589 (fun () -> Errors.fun_too_many_args p_sub p_super subtype_env.on_error)
2590 |> fun res ->
2591 match (ft_sub.ft_arity, ft_super.ft_arity) with
2592 | (Fvariadic { fp_name = None; _ }, Fvariadic { fp_name = Some _; _ }) ->
2593 (* The HHVM runtime ignores "..." entirely, but knows about
2594 * "...$args"; for contexts for which the runtime enforces method
2595 * compatibility (currently, inheritance from abstract/interface
2596 * methods), letting "..." override "...$args" would result in method
2597 * compatibility errors at runtime. *)
2598 with_error
2599 (fun () ->
2600 Errors.fun_variadicity_hh_vs_php56 p_sub p_super subtype_env.on_error)
2602 | (Fstandard, Fstandard) ->
2603 let sub_max = List.length ft_sub.ft_params in
2604 let super_max = List.length ft_super.ft_params in
2605 if sub_max < super_max then
2606 with_error
2607 (fun () -> Errors.fun_too_few_args p_sub p_super subtype_env.on_error)
2609 else
2611 | (Fstandard, _) ->
2612 with_error
2613 (fun () ->
2614 Errors.fun_unexpected_nonvariadic p_sub p_super subtype_env.on_error)
2616 | (_, _) -> res
2618 and simplify_subtype_possibly_enforced
2619 ~(subtype_env : subtype_env) et_sub et_super =
2620 simplify_subtype ~subtype_env et_sub.et_type et_super.et_type
2622 (* This implements basic subtyping on non-generic function types:
2623 * (1) return type behaves covariantly
2624 * (2) parameter types behave contravariantly
2625 * (3) special casing for variadics, and various reactivity and mutability attributes
2627 and simplify_subtype_funs
2628 ~(subtype_env : subtype_env)
2629 ~(check_return : bool)
2630 ?(extra_info : reactivity_extra_info option)
2631 (r_sub : Reason.t)
2632 (ft_sub : locl_fun_type)
2633 (r_super : Reason.t)
2634 (ft_super : locl_fun_type)
2635 env : env * TL.subtype_prop =
2636 let variadic_subtype =
2637 match ft_sub.ft_arity with
2638 | Fvariadic { fp_type = var_sub; _ } -> Some var_sub
2639 | _ -> None
2641 let variadic_supertype =
2642 match ft_super.ft_arity with
2643 | Fvariadic { fp_type = var_super; _ } -> Some var_super
2644 | _ -> None
2646 let simplify_subtype_possibly_enforced =
2647 simplify_subtype_possibly_enforced ~subtype_env
2649 let simplify_subtype_params = simplify_subtype_params ~subtype_env in
2650 (* First apply checks on attributes, coroutine-ness and variadic arity *)
2652 |> simplify_subtype_funs_attributes
2653 ~subtype_env
2654 ?extra_info
2655 r_sub
2656 ft_sub
2657 r_super
2658 ft_super
2659 &&& (* Now do contravariant subtyping on parameters *)
2660 begin
2661 match (variadic_subtype, variadic_supertype) with
2662 | (Some var_sub, Some var_super) ->
2663 simplify_subtype_possibly_enforced var_super var_sub
2664 | _ -> valid
2666 &&& begin
2667 let check_params_mutability =
2668 (not (equal_reactivity ft_super.ft_reactive Nonreactive))
2669 && not (equal_reactivity ft_sub.ft_reactive Nonreactive)
2671 let is_method =
2672 Option.equal
2673 Bool.equal
2674 (Option.map extra_info (fun i -> Option.is_some i.method_info))
2675 (Some true)
2677 simplify_subtype_params
2678 ~is_method
2679 ~check_params_reactivity:(should_check_fun_params_reactivity ft_super)
2680 ~check_params_mutability
2681 ft_super.ft_params
2682 ft_sub.ft_params
2683 variadic_subtype
2684 variadic_supertype
2687 (* Finally do covariant subtryping on return type *)
2688 if check_return then
2689 simplify_subtype_possibly_enforced ft_sub.ft_ret ft_super.ft_ret
2690 else
2691 valid
2693 (* One of the main entry points to this module *)
2694 and sub_type_i
2695 ~subtype_env (env : env) (ty_sub : internal_type) (ty_super : internal_type)
2696 : env =
2697 Env.log_env_change "sub_type" env
2699 let old_env = env in
2700 let (env, success) =
2701 sub_type_inner ~subtype_env env ~this_ty:None ty_sub ty_super
2703 if success then
2705 else
2706 old_env
2708 and sub_type env (ty_sub : locl_ty) (ty_super : locl_ty) on_error =
2709 sub_type_i
2710 ~subtype_env:(make_subtype_env ~treat_dynamic_as_bottom:false on_error)
2712 (LoclType ty_sub)
2713 (LoclType ty_super)
2715 (* Add a new upper bound ty on var. Apply transitivity of sutyping,
2716 * so if we already have tyl <: var, then check that for each ty_sub
2717 * in tyl we have ty_sub <: ty.
2719 and add_tyvar_upper_bound_and_close
2720 ~treat_dynamic_as_bottom (env, prop) var ty on_error =
2721 let upper_bounds_before = Env.get_tyvar_upper_bounds env var in
2722 let env =
2723 Env.add_tyvar_upper_bound_and_update_variances
2724 ~intersect:(try_intersect_i env)
2729 let upper_bounds_after = Env.get_tyvar_upper_bounds env var in
2730 let added_upper_bounds = ITySet.diff upper_bounds_after upper_bounds_before in
2731 let lower_bounds = Env.get_tyvar_lower_bounds env var in
2732 let (env, prop) =
2733 ITySet.fold
2734 (fun upper_bound (env, prop) ->
2735 let env =
2736 Typing_subtype_tconst.make_all_type_consts_equal
2739 upper_bound
2740 ~on_error
2741 ~as_tyvar_with_cnstr:true
2743 let env =
2744 Typing_subtype_pocket_universes.make_all_pu_equal
2747 upper_bound
2748 ~on_error
2750 ITySet.fold
2751 (fun lower_bound (env, prop1) ->
2752 let (env, prop2) =
2753 simplify_subtype_i
2754 ~subtype_env:
2755 (make_subtype_env ~treat_dynamic_as_bottom on_error)
2756 lower_bound
2757 upper_bound
2760 (env, TL.conj prop1 prop2))
2761 lower_bounds
2762 (env, prop))
2763 added_upper_bounds
2764 (env, prop)
2766 (env, prop)
2768 (* Add a new lower bound ty on var. Apply transitivity of subtyping
2769 * (so if var <: ty1,...,tyn then assert ty <: tyi for each tyi), using
2770 * simplify_subtype to produce a subtype proposition.
2772 and add_tyvar_lower_bound_and_close
2773 ~treat_dynamic_as_bottom (env, prop) var ty on_error =
2774 let lower_bounds_before = Env.get_tyvar_lower_bounds env var in
2775 let env =
2776 Env.add_tyvar_lower_bound_and_update_variances
2777 ~union:(try_union_i env)
2782 let lower_bounds_after = Env.get_tyvar_lower_bounds env var in
2783 let added_lower_bounds = ITySet.diff lower_bounds_after lower_bounds_before in
2784 let upper_bounds = Env.get_tyvar_upper_bounds env var in
2785 let (env, prop) =
2786 ITySet.fold
2787 (fun lower_bound (env, prop) ->
2788 let env =
2789 Typing_subtype_tconst.make_all_type_consts_equal
2792 lower_bound
2793 ~on_error
2794 ~as_tyvar_with_cnstr:false
2796 let env =
2797 Typing_subtype_pocket_universes.make_all_pu_equal
2800 lower_bound
2801 ~on_error
2803 ITySet.fold
2804 (fun upper_bound (env, prop1) ->
2805 let (env, prop2) =
2806 simplify_subtype_i
2807 ~subtype_env:
2808 (make_subtype_env ~treat_dynamic_as_bottom on_error)
2809 lower_bound
2810 upper_bound
2813 (env, TL.conj prop1 prop2))
2814 upper_bounds
2815 (env, prop))
2816 added_lower_bounds
2817 (env, prop)
2819 (env, prop)
2821 and get_tyvar_opt t =
2822 match t with
2823 | LoclType lt ->
2824 begin
2825 match get_node lt with
2826 | Tvar var -> Some var
2827 | _ -> None
2829 | _ -> None
2831 and props_to_env env remain props on_error =
2832 match props with
2833 | [] -> (env, List.rev remain)
2834 | prop :: props ->
2835 (match prop with
2836 | TL.Conj props' -> props_to_env env remain (props' @ props) on_error
2837 | TL.Disj (f, disj_props) ->
2838 (* For now, just find the first prop in the disjunction that works *)
2839 let rec try_disj disj_props =
2840 match disj_props with
2841 | [] ->
2842 (* For now let it fail later when calling
2843 process_simplify_subtype_result on the remaining constraints. *)
2844 props_to_env env (TL.invalid ~fail:f :: remain) props on_error
2845 | prop :: disj_props' ->
2846 let (env', other) = props_to_env env remain [prop] on_error in
2847 if TL.is_unsat (TL.conj_list other) then
2848 try_disj disj_props'
2849 else
2850 props_to_env env' (remain @ other) props on_error
2852 try_disj disj_props
2853 | TL.IsSubtype (ty_sub, ty_super) ->
2854 begin
2855 match (get_tyvar_opt ty_sub, get_tyvar_opt ty_super) with
2856 | (Some var_sub, Some var_super) ->
2857 let (env, prop1) =
2858 add_tyvar_upper_bound_and_close
2859 ~treat_dynamic_as_bottom:false
2860 (valid env)
2861 var_sub
2862 ty_super
2863 on_error
2865 let (env, prop2) =
2866 add_tyvar_lower_bound_and_close
2867 ~treat_dynamic_as_bottom:false
2868 (valid env)
2869 var_super
2870 ty_sub
2871 on_error
2873 props_to_env env remain (prop1 :: prop2 :: props) on_error
2874 | (Some var, _) ->
2875 let (env, prop) =
2876 add_tyvar_upper_bound_and_close
2877 ~treat_dynamic_as_bottom:false
2878 (valid env)
2880 ty_super
2881 on_error
2883 props_to_env env remain (prop :: props) on_error
2884 | (_, Some var) ->
2885 let (env, prop) =
2886 add_tyvar_lower_bound_and_close
2887 ~treat_dynamic_as_bottom:false
2888 (valid env)
2890 ty_sub
2891 on_error
2893 props_to_env env remain (prop :: props) on_error
2894 | _ -> props_to_env env (prop :: remain) props on_error
2896 | TL.Coerce (ty_sub, ty_super) ->
2897 begin
2898 match (get_node ty_sub, get_node ty_super) with
2899 | (Tvar var_sub, Tvar var_super) ->
2900 let (env, prop1) =
2901 add_tyvar_upper_bound_and_close
2902 ~treat_dynamic_as_bottom:true
2903 (valid env)
2904 var_sub
2905 (LoclType ty_super)
2906 on_error
2908 let (env, prop2) =
2909 add_tyvar_lower_bound_and_close
2910 ~treat_dynamic_as_bottom:true
2911 (valid env)
2912 var_super
2913 (LoclType ty_sub)
2914 on_error
2916 props_to_env env remain (prop1 :: prop2 :: props) on_error
2917 | (Tvar var, _) ->
2918 let (env, prop) =
2919 add_tyvar_upper_bound_and_close
2920 ~treat_dynamic_as_bottom:true
2921 (valid env)
2923 (LoclType ty_super)
2924 on_error
2926 props_to_env env remain (prop :: props) on_error
2927 | (_, Tvar var) ->
2928 let (env, prop) =
2929 add_tyvar_lower_bound_and_close
2930 ~treat_dynamic_as_bottom:true
2931 (valid env)
2933 (LoclType ty_sub)
2934 on_error
2936 props_to_env env remain (prop :: props) on_error
2937 | _ -> failwith "Coercion not expected"
2938 end)
2940 (* Move any top-level conjuncts of the form Tvar v <: t or t <: Tvar v to
2941 * the type variable environment. To do: use intersection and union to
2942 * simplify bounds.
2944 and prop_to_env env prop on_error =
2945 let (env, props') = props_to_env env [] [prop] on_error in
2946 (env, TL.conj_list props')
2948 and sub_type_inner
2949 (env : env)
2950 ~(subtype_env : subtype_env)
2951 ~(this_ty : locl_ty option)
2952 (ty_sub : internal_type)
2953 (ty_super : internal_type) : env * bool =
2954 log_subtype_i
2955 ~level:1
2956 ~this_ty
2957 ~function_name:"sub_type_inner"
2959 ty_sub
2960 ty_super;
2961 let (env, prop) =
2962 simplify_subtype_i ~subtype_env ~this_ty ty_sub ty_super env
2964 let (env, prop) = prop_to_env env prop subtype_env.on_error in
2965 let env = Env.add_subtype_prop env prop in
2966 let succeeded = process_simplify_subtype_result prop in
2967 (env, succeeded)
2969 and is_sub_type_alt_i
2970 ~ignore_generic_params ~no_top_bottom ~treat_dynamic_as_bottom env ty1 ty2 =
2971 let (this_ty, pos) =
2972 match ty1 with
2973 | LoclType ty1 -> (Some ty1, get_pos ty1)
2974 | ConstraintType _ -> (None, Pos.none)
2976 let (_env, prop) =
2977 simplify_subtype_i
2978 ~subtype_env:
2980 seen_generic_params =
2981 ( if ignore_generic_params then
2982 None
2983 else
2984 empty_seen );
2985 no_top_bottom;
2986 treat_dynamic_as_bottom;
2987 on_error = Errors.unify_error_at pos;
2989 ~this_ty
2990 (* It is weird that this can cause errors, but I am wary to discard them.
2991 * Using the generic unify_error to maintain current behavior. *)
2996 if TL.is_valid prop then
2997 Some true
2998 else if TL.is_unsat prop then
2999 Some false
3000 else
3001 None
3003 and is_sub_type_alt ~ignore_generic_params ~no_top_bottom env ty1 ty2 =
3004 is_sub_type_alt_i
3005 ~ignore_generic_params
3006 ~no_top_bottom
3008 (LoclType ty1)
3009 (LoclType ty2)
3011 and is_sub_type env ty1 ty2 =
3012 let ( = ) = Option.equal Bool.equal in
3013 is_sub_type_alt
3014 ~ignore_generic_params:false
3015 ~no_top_bottom:false
3016 ~treat_dynamic_as_bottom:false
3020 = Some true
3022 and is_sub_type_for_coercion env ty1 ty2 =
3023 let ( = ) = Option.equal Bool.equal in
3024 is_sub_type_alt
3025 ~ignore_generic_params:false
3026 ~no_top_bottom:false
3027 ~treat_dynamic_as_bottom:true
3031 = Some true
3033 and is_sub_type_for_union env ty1 ty2 =
3034 let ( = ) = Option.equal Bool.equal in
3035 is_sub_type_alt
3036 ~ignore_generic_params:false
3037 ~no_top_bottom:true
3038 ~treat_dynamic_as_bottom:false
3042 = Some true
3044 and is_sub_type_for_union_i env ty1 ty2 =
3045 let ( = ) = Option.equal Bool.equal in
3046 is_sub_type_alt_i
3047 ~ignore_generic_params:false
3048 ~no_top_bottom:true
3049 ~treat_dynamic_as_bottom:false
3053 = Some true
3055 and can_sub_type env ty1 ty2 =
3056 let ( <> ) a b = not (Option.equal Bool.equal a b) in
3057 is_sub_type_alt
3058 ~ignore_generic_params:false
3059 ~no_top_bottom:true
3060 ~treat_dynamic_as_bottom:false
3064 <> Some false
3066 and is_sub_type_ignore_generic_params env ty1 ty2 =
3067 let ( = ) = Option.equal Bool.equal in
3068 is_sub_type_alt
3069 ~ignore_generic_params:true
3070 ~no_top_bottom:true
3071 ~treat_dynamic_as_bottom:false
3075 = Some true
3077 and is_sub_type_ignore_generic_params_i env ty1 ty2 =
3078 let ( = ) = Option.equal Bool.equal in
3079 is_sub_type_alt_i
3080 ~ignore_generic_params:true
3081 ~no_top_bottom:true
3082 ~treat_dynamic_as_bottom:false
3086 = Some true
3088 (* Attempt to compute the intersection of a type with an existing list intersection.
3089 * If try_intersect env t [t1;...;tn] = [u1; ...; um]
3090 * then u1&...&um must be the greatest lower bound of t and t1&...&tn wrt subtyping.
3091 * For example:
3092 * try_intersect nonnull [?C] = [C]
3093 * try_intersect t1 [t2] = [t1] if t1 <: t2
3094 * Note: it's acceptable to return [t;t1;...;tn] but the intention is that
3095 * we simplify (as above) wherever practical.
3096 * It can be assumed that the original list contains no redundancy.
3098 and try_intersect_i env ty tyl =
3099 match tyl with
3100 | [] -> [ty]
3101 | ty' :: tyl' ->
3102 if is_sub_type_ignore_generic_params_i env ty ty' then
3103 try_intersect_i env ty tyl'
3104 else if is_sub_type_ignore_generic_params_i env ty' ty then
3106 else
3107 let nonnull_ty = LoclType (MakeType.nonnull (reason ty)) in
3108 let (env, ty) = Env.expand_internal_type env ty in
3109 let (env, ty') = Env.expand_internal_type env ty' in
3110 let default () = ty' :: try_intersect_i env ty tyl' in
3111 (match (ty, ty') with
3112 | (LoclType lty, _)
3113 when is_sub_type_ignore_generic_params_i env ty' nonnull_ty ->
3114 begin
3115 match get_node lty with
3116 | Toption t -> try_intersect_i env (LoclType t) (ty' :: tyl')
3117 | _ -> default ()
3119 | (_, LoclType lty)
3120 when is_sub_type_ignore_generic_params_i env ty nonnull_ty ->
3121 begin
3122 match get_node lty with
3123 | Toption t -> try_intersect_i env (LoclType t) (ty :: tyl')
3124 | _ -> default ()
3126 | (_, _) -> default ())
3128 and try_intersect env ty tyl =
3129 List.map
3130 (try_intersect_i
3132 (LoclType ty)
3133 (List.map tyl ~f:(fun ty -> LoclType ty)))
3134 ~f:(function
3135 | LoclType ty -> ty
3136 | _ ->
3137 failwith
3138 "The intersection of two locl type should always be a locl type.")
3140 (* Attempt to compute the union of a type with an existing list union.
3141 * If try_union env t [t1;...;tn] = [u1;...;um]
3142 * then u1|...|um must be the least upper bound of t and t1|...|tn wrt subtyping.
3143 * For example:
3144 * try_union int [float] = [num]
3145 * try_union t1 [t2] = [t1] if t2 <: t1
3147 * Notes:
3148 * 1. It's acceptable to return [t;t1;...;tn] but the intention is that
3149 * we simplify (as above) wherever practical.
3150 * 2. Do not use Tunion for a syntactic union - the caller can do that.
3151 * 3. It can be assumed that the original list contains no redundancy.
3152 * TODO: there are many more unions to implement yet.
3154 and try_union_i env ty tyl =
3155 match tyl with
3156 | [] -> [ty]
3157 | ty' :: tyl' ->
3158 if is_sub_type_for_union_i env ty ty' then
3160 else if is_sub_type_for_union_i env ty' ty then
3161 try_union_i env ty tyl'
3162 else
3163 let (env, ty) = Env.expand_internal_type env ty in
3164 let (env, ty') = Env.expand_internal_type env ty' in
3165 (match (ty, ty') with
3166 | (LoclType t1, LoclType t2)
3167 when (is_prim Nast.Tfloat t1 && is_prim Nast.Tint t2)
3168 || (is_prim Nast.Tint t1 && is_prim Nast.Tfloat t2) ->
3169 let num = LoclType (MakeType.num (reason ty)) in
3170 try_union_i env num tyl'
3171 | (_, _) -> ty' :: try_union_i env ty tyl')
3173 and try_union env ty tyl =
3174 List.map
3175 (try_union_i env (LoclType ty) (List.map tyl ~f:(fun ty -> LoclType ty)))
3176 ~f:(function
3177 | LoclType ty -> ty
3178 | _ -> failwith "The union of two locl type should always be a locl type.")
3180 let subtype_reactivity
3181 ?extra_info ?is_call_site env p_sub r_sub p_super r_super on_error =
3182 let subtype_env = make_subtype_env ~treat_dynamic_as_bottom:false on_error in
3183 let (env, prop) =
3184 simplify_subtype_reactivity
3185 ~subtype_env
3186 ?extra_info
3187 ?is_call_site
3188 p_sub
3189 r_sub
3190 p_super
3191 r_super
3194 let (env, prop) = prop_to_env env prop subtype_env.on_error in
3195 ignore (process_simplify_subtype_result prop);
3198 let decompose_subtype_add_bound
3199 (env : env) (ty_sub : locl_ty) (ty_super : locl_ty) : env =
3200 let (env, ty_super) = Env.expand_type env ty_super in
3201 let (env, ty_sub) = Env.expand_type env ty_sub in
3202 match (get_node ty_sub, get_node ty_super) with
3203 | (_, Tany _) -> env
3204 (* name_sub <: ty_super so add an upper bound on name_sub *)
3205 | (Tgeneric (name_sub, _targs), _) when not (phys_equal ty_sub ty_super) ->
3206 (* TODO(T69551141) handle type arguments *)
3207 log_subtype
3208 ~level:2
3209 ~this_ty:None
3210 ~function_name:"decompose_subtype_add_bound"
3212 ty_sub
3213 ty_super;
3214 let tys = Env.get_upper_bounds env name_sub in
3215 (* Don't add the same type twice! *)
3216 if Typing_set.mem ty_super tys then
3218 else
3219 Env.add_upper_bound ~intersect:(try_intersect env) env name_sub ty_super
3220 (* ty_sub <: name_super so add a lower bound on name_super *)
3221 | (_, Tgeneric (name_super, _targs)) when not (phys_equal ty_sub ty_super) ->
3222 (* TODO(T69551141) handle type arguments *)
3223 log_subtype
3224 ~level:2
3225 ~this_ty:None
3226 ~function_name:"decompose_subtype_add_bound"
3228 ty_sub
3229 ty_super;
3230 let tys = Env.get_lower_bounds env name_super in
3231 (* Don't add the same type twice! *)
3232 if Typing_set.mem ty_sub tys then
3234 else
3235 Env.add_lower_bound ~union:(try_union env) env name_super ty_sub
3236 | (_, _) -> env
3238 (* Given two types that we know are in a subtype relationship
3239 * ty_sub <: ty_super
3240 * add to env.tpenv any bounds on generic type parameters that must
3241 * hold for ty_sub <: ty_super to be valid.
3243 * For example, suppose we know Cov<T> <: Cov<D> for a covariant class Cov.
3244 * Then it must be the case that T <: D so we add an upper bound D to the
3245 * bounds for T.
3247 * Although some of this code is similar to that for sub_type_inner, its
3248 * purpose is different. sub_type_inner takes two types t and u and makes
3249 * updates to the substitution of type variables (through unification) to
3250 * make t <: u true.
3252 * decompose_subtype takes two types t and u for which t <: u is *assumed* to
3253 * hold, and makes updates to bounds on generic parameters that *necessarily*
3254 * hold in order for t <: u.
3256 let rec decompose_subtype
3258 (env : env)
3259 (ty_sub : locl_ty)
3260 (ty_super : locl_ty)
3261 (on_error : Errors.typing_error_callback) : env =
3262 log_subtype
3263 ~level:2
3264 ~this_ty:None
3265 ~function_name:"decompose_subtype"
3267 ty_sub
3268 ty_super;
3269 let (env, prop) =
3270 simplify_subtype
3271 ~subtype_env:(make_subtype_env ~seen_generic_params:None on_error)
3272 ~this_ty:None
3273 ty_sub
3274 ty_super
3277 decompose_subtype_add_prop p env prop
3279 and decompose_subtype_add_prop p env prop =
3280 match prop with
3281 | TL.Conj props ->
3282 List.fold_left ~f:(decompose_subtype_add_prop p) ~init:env props
3283 | TL.Disj (_, []) -> Env.mark_inconsistent env
3284 | TL.Disj (_, [prop']) -> decompose_subtype_add_prop p env prop'
3285 | TL.Disj _ ->
3286 Typing_log.log_prop 2 env.function_pos "decompose_subtype_add_prop" env prop;
3288 | TL.Coerce _ -> failwith "Coercions should have been resolved beforehand"
3289 | TL.IsSubtype (LoclType ty1, LoclType ty2) ->
3290 decompose_subtype_add_bound env ty1 ty2
3291 | TL.IsSubtype _ ->
3292 failwith
3293 "Subtyping locl types should yield propositions involving locl types only."
3295 (* Decompose a general constraint *)
3296 and decompose_constraint
3298 (env : env)
3299 (ck : Ast_defs.constraint_kind)
3300 (ty_sub : locl_ty)
3301 (ty_super : locl_ty) : env =
3302 (* constraints are caught based on reason, not error callback. Using unify_error *)
3303 match ck with
3304 | Ast_defs.Constraint_as ->
3305 decompose_subtype p env ty_sub ty_super (Errors.unify_error_at p)
3306 | Ast_defs.Constraint_super ->
3307 decompose_subtype p env ty_super ty_sub (Errors.unify_error_at p)
3308 | Ast_defs.Constraint_eq ->
3309 let env =
3310 decompose_subtype p env ty_sub ty_super (Errors.unify_error_at p)
3312 decompose_subtype p env ty_super ty_sub (Errors.unify_error_at p)
3314 (* Given a constraint ty1 ck ty2 where ck is AS, SUPER or =,
3315 * add bounds to type parameters in the environment that necessarily
3316 * must hold in order for ty1 ck ty2.
3318 * First, we invoke decompose_constraint to add initial bounds to
3319 * the environment. Then we iterate, decomposing constraints that
3320 * arise through transitivity across bounds.
3322 * For example, suppose that env already contains
3323 * C<T1> <: T2
3324 * for some covariant class C. Now suppose we add the
3325 * constraint "T2 as C<T3>" i.e. we end up with
3326 * C<T1> <: T2 <: C<T3>
3327 * Then by transitivity we know that T1 <: T3 so we add this to the
3328 * environment too.
3330 * We repeat this process until no further bounds are added to the
3331 * environment, or some limit is reached. (It's possible to construct
3332 * types that expand forever under inheritance.)
3334 let constraint_iteration_limit = 20
3336 let add_constraint
3338 (env : env)
3339 (ck : Ast_defs.constraint_kind)
3340 (ty_sub : locl_ty)
3341 (ty_super : locl_ty) : env =
3342 log_subtype
3343 ~level:1
3344 ~this_ty:None
3345 ~function_name:"add_constraint"
3347 ty_sub
3348 ty_super;
3349 let oldsize = Env.get_tpenv_size env in
3350 let env = decompose_constraint p env ck ty_sub ty_super in
3351 let ( = ) = Int.equal in
3352 if Env.get_tpenv_size env = oldsize then
3354 else
3355 let rec iter n env =
3356 if n > constraint_iteration_limit then
3358 else
3359 let oldsize = Env.get_tpenv_size env in
3360 let env =
3361 List.fold_left
3362 (Env.get_generic_parameters env)
3363 ~init:env
3364 ~f:(fun env x ->
3365 List.fold_left
3366 (Typing_set.elements (Env.get_lower_bounds env x))
3367 ~init:env
3368 ~f:(fun env ty_sub' ->
3369 List.fold_left
3370 (Typing_set.elements (Env.get_upper_bounds env x))
3371 ~init:env
3372 ~f:(fun env ty_super' ->
3373 decompose_subtype
3376 ty_sub'
3377 ty_super'
3378 (Errors.unify_error_at p))))
3380 if Int.equal (Env.get_tpenv_size env) oldsize then
3382 else
3383 iter (n + 1) env
3385 iter 0 env
3387 let add_constraints p env constraints =
3388 let add_constraint env (ty1, ck, ty2) = add_constraint p env ck ty1 ty2 in
3389 List.fold_left constraints ~f:add_constraint ~init:env
3391 let sub_type_with_dynamic_as_bottom
3392 (env : env)
3393 (ty_sub : locl_ty)
3394 (ty_super : locl_ty)
3395 (on_error : Errors.typing_error_callback) : env =
3396 let env_change_log = Env.log_env_change "coercion" env in
3397 log_subtype
3398 ~level:1
3399 ~this_ty:None
3400 ~function_name:"coercion"
3402 ty_sub
3403 ty_super;
3404 let old_env = env in
3405 let (env, prop) =
3406 simplify_subtype
3407 ~subtype_env:(make_subtype_env ~treat_dynamic_as_bottom:true on_error)
3408 ~this_ty:None
3409 ty_sub
3410 ty_super
3413 let (env, prop) = prop_to_env env prop on_error in
3414 let env = Env.add_subtype_prop env prop in
3415 let succeeded = process_simplify_subtype_result prop in
3416 let env =
3417 if succeeded then
3419 else
3420 old_env
3422 env_change_log env
3424 let simplify_subtype_i env ty_sub ty_super ~on_error =
3425 simplify_subtype_i
3426 ~subtype_env:(make_subtype_env ~no_top_bottom:true on_error)
3427 ty_sub
3428 ty_super
3431 (*****************************************************************************)
3432 (* Exporting *)
3433 (*****************************************************************************)
3435 let sub_type_i env ty1 ty2 on_error =
3436 sub_type_i
3437 ~subtype_env:(make_subtype_env ~treat_dynamic_as_bottom:false on_error)
3442 let subtype_funs
3443 ~(check_return : bool)
3444 ~(extra_info : reactivity_extra_info)
3445 ~on_error
3446 (r_sub : Reason.t)
3447 (ft_sub : locl_fun_type)
3448 (r_super : Reason.t)
3449 (ft_super : locl_fun_type)
3450 env : env =
3451 let old_env = env in
3452 let (env, prop) =
3453 simplify_subtype_funs
3454 ~subtype_env:(make_subtype_env on_error)
3455 ~check_return
3456 ~extra_info
3457 r_sub
3458 ft_sub
3459 r_super
3460 ft_super
3463 let (env, prop) = prop_to_env env prop on_error in
3464 let env = Env.add_subtype_prop env prop in
3465 let succeeded = process_simplify_subtype_result prop in
3466 if succeeded then
3468 else
3469 old_env
3471 let sub_type_or_fail env ty1 ty2 fail =
3472 sub_type env ty1 ty2 (fun ?code:_ _ -> fail ())
3474 let set_fun_refs () =
3475 Typing_utils.sub_type_ref := sub_type;
3476 Typing_utils.sub_type_i_ref := sub_type_i;
3477 Typing_utils.sub_type_with_dynamic_as_bottom_ref :=
3478 sub_type_with_dynamic_as_bottom;
3479 Typing_utils.add_constraint_ref := add_constraint;
3480 Typing_utils.is_sub_type_ref := is_sub_type;
3481 Typing_utils.is_sub_type_for_union_ref := is_sub_type_for_union;
3482 Typing_utils.is_sub_type_for_union_i_ref := is_sub_type_for_union_i;
3483 Typing_utils.is_sub_type_ignore_generic_params_ref :=
3484 is_sub_type_ignore_generic_params
3486 let () = set_fun_refs ()