Pretty print capabilities in generic subtyping errors
[hiphop-php.git] / hphp / hack / src / typing / typing_subtype.ml
blob69122a91bd1ef0e8e0c9cb0fd1ca39f40976403f
1 (*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
10 open Hh_prelude
11 open Common
12 open Utils
13 open Typing_defs
14 open Typing_env_types
15 open Typing_logic_helpers
16 module Reason = Typing_reason
17 module Env = Typing_env
18 module Inter = Typing_intersection
19 module TUtils = Typing_utils
20 module SN = Naming_special_names
21 module Phase = Typing_phase
22 module TL = Typing_logic
23 module Cls = Decl_provider.Class
24 module ITySet = Internal_type_set
25 module MakeType = Typing_make_type
26 module Partial = Partial_provider
27 module ShapeMap = Nast.ShapeMap
28 module ShapeSet = Ast_defs.ShapeSet
29 module Nast = Aast
31 type subtype_env = {
32 seen_generic_params: SSet.t option;
33 no_top_bottom: bool;
34 treat_dynamic_as_bottom: bool;
35 (* Used with global flag --enable-sound-dynamic-type, allow_subtype_of_dynamic
36 controls whether types that implement dynamic can be subtypes of dynamic *)
37 allow_subtype_of_dynamic: bool;
38 on_error: Errors.typing_error_callback;
41 let empty_seen = Some SSet.empty
43 let make_subtype_env
44 ?(seen_generic_params = empty_seen)
45 ?(no_top_bottom = false)
46 ?(treat_dynamic_as_bottom = false)
47 ?(allow_subtype_of_dynamic = false)
48 on_error =
50 seen_generic_params;
51 no_top_bottom;
52 treat_dynamic_as_bottom;
53 allow_subtype_of_dynamic;
54 on_error;
57 let add_seen_generic subtype_env name =
58 match subtype_env.seen_generic_params with
59 | Some seen ->
60 { subtype_env with seen_generic_params = Some (SSet.add name seen) }
61 | None -> subtype_env
63 type reactivity_extra_info = {
64 method_info: (* method_name *) (string * (* is_static *) bool) option;
65 class_ty: phase_ty option;
66 parent_class_ty: phase_ty option;
69 let empty_extra_info =
70 { method_info = None; class_ty = None; parent_class_ty = None }
72 module ConditionTypes = struct
73 let try_get_class_for_condition_type (env : env) (ty : decl_ty) =
74 match TUtils.try_unwrap_class_type ty with
75 | None -> None
76 | Some (_, ((_, x) as sid), _) ->
77 begin
78 match Env.get_class env x with
79 | None -> None
80 | Some cls -> Some (sid, cls)
81 end
83 let try_get_method_from_condition_type
84 (env : env) (ty : decl_ty) (is_static : bool) (method_name : string) =
85 match try_get_class_for_condition_type env ty with
86 | Some (_, cls) ->
87 let get =
88 if is_static then
89 Cls.get_smethod
90 else
91 Cls.get_method
93 get cls method_name
94 | None -> None
96 let localize_condition_type (env : env) (ty : decl_ty) : locl_ty =
97 (* if condition type is generic - we cannot specify type argument in attribute.
98 For cases when we check if containing type is a subtype of condition type
99 if condition type is generic instantiate it with TAny's *)
100 let do_localize ty =
101 let ty =
102 match try_get_class_for_condition_type env ty with
103 | None -> ty
104 | Some (((p, _) as sid), cls) ->
105 let tparams = Cls.tparams cls in
106 if List.is_empty tparams then
108 else
109 let params =
110 List.map tparams ~f:(fun { tp_name = (p, x); _ } ->
111 (* TODO(T69551141) handle type arguments *)
112 MakeType.generic (Reason.Rwitness p) x)
114 let subst = Decl_instantiate.make_subst tparams [] in
115 let ty = MakeType.apply (Reason.Rwitness p) sid params in
116 Decl_instantiate.instantiate subst ty
118 let ety_env = Phase.env_with_self env in
119 let (_, t) = Phase.localize ~ety_env env ty in
122 match deref ty with
123 | (r, Toption ty) -> mk (r, Toption (do_localize ty))
124 | _ -> do_localize ty
127 (* Given a pair of types `ty_sub` and `ty_super` attempt to apply simplifications
128 * and add to the accumulated constraints in `constraints` any necessary and
129 * sufficient [(t1,ck1,u1);...;(tn,ckn,un)] such that
130 * ty_sub <: ty_super iff t1 ck1 u1, ..., tn ckn un
131 * where ck is `as` or `=`. Essentially we are making solution-preserving
132 * simplifications to the subtype assertion, for now, also generating equalities
133 * as well as subtype assertions, for backwards compatibility with use of
134 * unification.
136 * If `constraints = []` is returned then the subtype assertion is valid.
138 * If the subtype assertion is unsatisfiable then return `failed = Some f`
139 * where `f` is a `unit-> unit` function that records an error message.
140 * (Sometimes we don't want to call this function e.g. when just checking if
141 * a subtype holds)
143 * Elide singleton unions, treat invariant generics as both-ways
144 * subtypes, and actually chase hierarchy for extends and implements.
146 * Annoyingly, we need to pass env back too, because Typing_phase.localize
147 * expands type constants. (TODO: work out a better way of handling this)
149 * Special cases:
150 * If assertion is valid (e.g. string <: arraykey) then
151 * result can be the empty list (i.e. nothing is added to the result)
152 * If assertion is unsatisfiable (e.g. arraykey <: string) then
153 * we record this in the failed field of the result.
156 (** Check that a mutability type is a subtype of another mutability type *)
157 let check_mutability
158 ~(is_receiver : bool)
159 ~subtype_env
160 (p_sub : Pos.t)
161 (mut_sub : param_mutability option)
162 (p_super : Pos.t)
163 (mut_super : param_mutability option)
164 env =
165 let str m =
166 match m with
167 | None -> "immutable"
168 | Some Param_owned_mutable -> "owned mutable"
169 | Some Param_borrowed_mutable -> "mutable"
170 | Some Param_maybe_mutable -> "maybe-mutable"
172 (* maybe-mutable <------immutable
174 <--mutable <-- owned mutable *)
175 match (mut_sub, mut_super) with
176 (* immutable is not compatible with mutable *)
177 | (None, Some (Param_borrowed_mutable | Param_owned_mutable))
178 (* mutable is not compatible with immutable *)
179 | (Some (Param_borrowed_mutable | Param_owned_mutable), None)
180 (* borrowed mutable is not compatible with owned mutable *)
181 | (Some Param_borrowed_mutable, Some Param_owned_mutable)
182 (* maybe-mutable is not compatible with immutable/mutable *)
183 | ( Some Param_maybe_mutable,
184 (None | Some (Param_borrowed_mutable | Param_owned_mutable)) ) ->
185 invalid
186 ~fail:(fun () ->
187 Errors.mutability_mismatch
188 ~is_receiver
189 p_sub
190 (str mut_sub)
191 p_super
192 (str mut_super)
193 subtype_env.on_error)
195 | _ -> valid env
197 let log_subtype_i ~level ~this_ty ~function_name env ty_sub ty_super =
198 Typing_log.(
199 log_with_level env "sub" level (fun () ->
200 let types =
201 [Log_type_i ("ty_sub", ty_sub); Log_type_i ("ty_super", ty_super)]
203 let types =
204 Option.value_map this_ty ~default:types ~f:(fun ty ->
205 Log_type ("this_ty", ty) :: types)
207 log_types
208 (Reason.to_pos (reason ty_sub))
210 [Log_head (function_name, types)]))
212 let log_subtype ~this_ty ~function_name env ty_sub ty_super =
213 log_subtype_i
214 ~this_ty
215 ~function_name
217 (LoclType ty_sub)
218 (LoclType ty_super)
220 let is_final_and_not_contravariant env id =
221 let class_def = Env.get_class env id in
222 match class_def with
223 | Some class_ty -> TUtils.class_is_final_and_not_contravariant class_ty
224 | None -> false
226 (** Make all types appearing in the given type a Tany, e.g.
227 - for A<B> return A<_>
228 - for function(A): B return function (_): _
230 let anyfy env r ty =
231 let anyfyer =
232 object
233 inherit Type_mapper.deep_type_mapper as super
235 method! on_type env _ty = (env, mk (r, Typing_defs.make_tany ()))
237 method go ty =
238 let (_, ty) = super#on_type env ty in
242 anyfyer#go ty
244 let find_type_with_exact_negation env tyl =
245 let rec find env tyl acc_tyl =
246 match tyl with
247 | [] -> (env, None, acc_tyl)
248 | ty :: tyl' ->
249 let (env, non_ty) = TUtils.non env (get_reason ty) ty TUtils.ApproxDown in
250 let nothing = MakeType.nothing Reason.none in
251 if ty_equal non_ty nothing then
252 find env tyl' (ty :: acc_tyl)
253 else
254 (env, Some non_ty, tyl' @ acc_tyl)
256 find env tyl []
258 let rec describe_ty_super env ty =
259 let print ty =
260 Typing_print.with_blank_tyvars (fun () ->
261 Typing_print.full_strip_ns_i env ty)
263 let default () = print ty in
264 match ty with
265 | LoclType ty ->
266 let (env, ty) = Env.expand_type env ty in
267 (match get_node ty with
268 | Tvar v ->
269 let upper_bounds = ITySet.elements (Env.get_tyvar_upper_bounds env v) in
270 (* The constraint graph is transitively closed so we can filter tyvars. *)
271 let is_not_tyvar = function
272 | LoclType t -> not (is_tyvar t)
273 | _ -> true
275 let upper_bounds = List.filter upper_bounds ~f:is_not_tyvar in
276 (match upper_bounds with
277 | [] -> "some type not known yet"
278 | tyl ->
279 let (locl_tyl, cstr_tyl) = List.partition_tf tyl ~f:is_locl_type in
280 let sep =
281 match (locl_tyl, cstr_tyl) with
282 | (_ :: _, _ :: _) -> " and "
283 | _ -> ""
285 let locl_descr =
286 match locl_tyl with
287 | [] -> ""
288 | tyl ->
289 "of type "
290 ^ ( String.concat ~sep:" & " (List.map tyl ~f:print)
291 |> Markdown_lite.md_codify )
293 let cstr_descr =
294 String.concat
295 ~sep:" and "
296 (List.map cstr_tyl ~f:(describe_ty_super env))
298 "something " ^ locl_descr ^ sep ^ cstr_descr)
299 | Toption ty when is_tyvar ty ->
300 "`null` or " ^ describe_ty_super env (LoclType ty)
301 | _ -> Markdown_lite.md_codify (default ()))
302 | ConstraintType ty ->
303 (match deref_constraint_type ty with
304 | (_, Thas_member hm) ->
305 let {
306 hm_name = (_, name);
307 hm_type = _;
308 hm_class_id = _;
309 hm_explicit_targs = targs;
313 (match targs with
314 | None -> Printf.sprintf "an object with property `%s`" name
315 | Some _ -> Printf.sprintf "an object with method `%s`" name)
316 | (_, Tdestructure _) ->
317 Markdown_lite.md_codify
318 (Typing_print.with_blank_tyvars (fun () ->
319 Typing_print.full_strip_ns_i env (ConstraintType ty)))
320 | (_, TCunion (lty, cty)) ->
321 Printf.sprintf
322 "%s or %s"
323 (describe_ty_super env (LoclType lty))
324 (describe_ty_super env (ConstraintType cty))
325 | (_, TCintersection (lty, cty)) ->
326 Printf.sprintf
327 "%s and %s"
328 (describe_ty_super env (LoclType lty))
329 (describe_ty_super env (ConstraintType cty)))
331 (** Process the constraint proposition. There should only be errors left now,
332 i.e. empty disjunction with error functions we call here. *)
333 let rec process_simplify_subtype_result prop =
334 match prop with
335 | TL.IsSubtype (_ty1, _ty2) ->
336 (* All subtypes should have been resolved *)
337 failwith "unexpected subtype assertion"
338 | TL.Coerce _ ->
339 (* All coercions should have been resolved *)
340 failwith "unexpected coercions assertion"
341 | TL.Conj props ->
342 (* Evaluates list from left-to-right so preserves order of conjuncts *)
343 List.for_all ~f:process_simplify_subtype_result props
344 | TL.Disj (f, []) ->
345 f ();
346 false
347 | TL.Disj _ -> failwith "non-empty disjunction"
349 and simplify_subtype
350 ~(subtype_env : subtype_env)
351 ?(this_ty : locl_ty option = None)
352 ty_sub
353 ty_super =
354 simplify_subtype_i ~subtype_env ~this_ty (LoclType ty_sub) (LoclType ty_super)
356 and default_subtype
357 ~subtype_env ~(this_ty : locl_ty option) ~fail env ty_sub ty_super =
358 let default env = (env, TL.IsSubtype (ty_sub, ty_super)) in
359 let ( ||| ) = ( ||| ) ~fail in
360 let (env, ty_super) = Env.expand_internal_type env ty_super in
361 let (env, ty_sub) = Env.expand_internal_type env ty_sub in
362 let default_subtype_inner env ty_sub ty_super =
363 (* This inner function contains typing rules that are based solely on the subtype
364 * if you need to pattern match on the super type it should NOT be included
365 * here
367 match ty_sub with
368 | ConstraintType cty_sub ->
369 begin
370 match deref_constraint_type cty_sub with
371 | (_, TCunion (lty_sub, cty_sub)) ->
373 |> simplify_subtype_i ~subtype_env (LoclType lty_sub) ty_super
374 &&& simplify_subtype_i ~subtype_env (ConstraintType cty_sub) ty_super
375 | (_, TCintersection (lty_sub, cty_sub)) ->
377 |> simplify_subtype_i ~subtype_env (LoclType lty_sub) ty_super
378 ||| simplify_subtype_i ~subtype_env (ConstraintType cty_sub) ty_super
379 | _ -> invalid ~fail env
381 | LoclType lty_sub ->
383 * t1 | ... | tn <: t
384 * if and only if
385 * t1 <: t /\ ... /\ tn <: t
386 * We want this even if t is a type variable e.g. consider
387 * int | v <: v
389 begin
390 match deref lty_sub with
391 | (_, Tunion tyl) ->
392 List.fold_left tyl ~init:(env, TL.valid) ~f:(fun res ty_sub ->
393 res &&& simplify_subtype_i ~subtype_env (LoclType ty_sub) ty_super)
394 | (_, Terr) ->
395 if subtype_env.no_top_bottom then
396 default env
397 else
398 valid env
399 | (_, Tvar _) -> default env
400 | (r_sub, Tintersection tyl) ->
401 (* A & B <: C iif A <: C | !B *)
402 (match find_type_with_exact_negation env tyl with
403 | (env, Some non_ty, tyl) ->
404 let (env, ty_super) =
405 TUtils.union_i env (get_reason non_ty) ty_super non_ty
407 let ty_sub = MakeType.intersection r_sub tyl in
408 simplify_subtype_i ~subtype_env (LoclType ty_sub) ty_super env
409 | _ ->
410 (* It's sound to reduce t1 & t2 <: t to (t1 <: t) || (t2 <: t), but
411 * not complete.
413 List.fold_left
415 ~init:(env, TL.invalid ~fail)
416 ~f:(fun res ty_sub ->
417 let ty_sub = LoclType ty_sub in
418 res ||| simplify_subtype_i ~subtype_env ~this_ty ty_sub ty_super))
419 | (_, Tgeneric (name_sub, tyargs)) ->
420 (* TODO(T69551141) handle type arguments. right now, just passin tyargs to
421 Env.get_upper_bounds *)
422 (match subtype_env.seen_generic_params with
423 | None -> default env
424 | Some seen ->
425 (* If we've seen this type parameter before then we must have gone
426 * round a cycle so we fail
428 if SSet.mem name_sub seen then
429 invalid ~fail env
430 else
431 (* If the generic is actually an expression dependent type,
432 we need to update this_ty
434 let this_ty =
436 DependentKind.is_generic_dep_ty name_sub
437 && Option.is_none this_ty
438 then
439 Some lty_sub
440 else
441 this_ty
443 let subtype_env = add_seen_generic subtype_env name_sub in
444 (* Otherwise, we collect all the upper bounds ("as" constraints) on
445 the generic parameter, and check each of these in turn against
446 ty_super until one of them succeeds
448 let rec try_bounds tyl env =
449 match tyl with
450 | [] ->
451 (* Try an implicit mixed = ?nonnull bound before giving up.
452 This can be useful when checking T <: t, where type t is
453 equivalent to but syntactically different from ?nonnull.
454 E.g., if t is a generic type parameter T with nonnull as
455 a lower bound.
457 let r =
458 Reason.Rimplicit_upper_bound (get_pos lty_sub, "?nonnull")
460 let tmixed = LoclType (MakeType.mixed r) in
462 |> simplify_subtype_i ~subtype_env ~this_ty tmixed ty_super
463 | [ty] ->
464 simplify_subtype_i
465 ~subtype_env
466 ~this_ty
467 (LoclType ty)
468 ty_super
470 | ty :: tyl ->
472 |> try_bounds tyl
473 ||| simplify_subtype_i
474 ~subtype_env
475 ~this_ty
476 (LoclType ty)
477 ty_super
480 |> try_bounds
481 (Typing_set.elements
482 (Env.get_upper_bounds env name_sub tyargs)))
483 |> (* Turn error into a generic error about the type parameter *)
484 if_unsat (invalid ~fail)
485 | (_, Tdynamic) when subtype_env.treat_dynamic_as_bottom -> valid env
486 | (_, Taccess _) -> invalid ~fail env
487 | _ -> invalid ~fail env
490 (* We further refine the default subtype case for rules that apply to all
491 * LoclTypes but not to ConstraintTypes
493 match ty_super with
494 | LoclType lty_super ->
495 (match ty_sub with
496 | ConstraintType _ -> default_subtype_inner env ty_sub ty_super
497 | LoclType lty_sub ->
498 begin
499 match deref lty_sub with
500 | (_, Tvar _) when subtype_env.treat_dynamic_as_bottom ->
501 (env, TL.Coerce (lty_sub, lty_super))
502 | (_, Tnewtype (_, _, ty)) ->
503 simplify_subtype ~subtype_env ~this_ty ty lty_super env
504 | (_, Tdependent (_, ty)) ->
505 let this_ty = Option.first_some this_ty (Some lty_sub) in
506 simplify_subtype ~subtype_env ~this_ty ty lty_super env
507 | (r_sub, Tany _) ->
508 if subtype_env.no_top_bottom then
509 default env
510 else
511 let ty_sub = anyfy env r_sub lty_super in
512 simplify_subtype ~subtype_env ~this_ty ty_sub lty_super env
513 | (r_sub, Tprim Nast.Tvoid) ->
514 let r =
515 Reason.Rimplicit_upper_bound (Reason.to_pos r_sub, "?nonnull")
517 simplify_subtype
518 ~subtype_env
519 ~this_ty
520 (MakeType.mixed r)
521 lty_super
523 |> if_unsat (invalid ~fail)
524 | _ -> default_subtype_inner env ty_sub ty_super
525 end)
526 | ConstraintType _ -> default_subtype_inner env ty_sub ty_super
528 (* Attempt to "solve" a subtype assertion ty_sub <: ty_super.
529 * Return a proposition that is equivalent, but simpler, than
530 * the original assertion. Fail with Unsat error_function if
531 * the assertion is unsatisfiable. Some examples:
532 * string <: arraykey ==> True (represented as Conj [])
533 * (For covariant C and a type variable v)
534 * C<string> <: C<v> ==> string <: v
535 * (Assuming that C does *not* implement interface J)
536 * C <: J ==> Unsat _
537 * (Assuming we have T <: D in tpenv, and class D implements I)
538 * vec<T> <: vec<I> ==> True
539 * This last one would be left as T <: I if seen_generic_params is None
541 and simplify_subtype_i
542 ~(subtype_env : subtype_env)
543 ?(this_ty : locl_ty option = None)
544 (ty_sub : internal_type)
545 (ty_super : internal_type)
546 env : env * TL.subtype_prop =
547 log_subtype_i
548 ~level:2
549 ~this_ty
550 ~function_name:"simplify_subtype"
552 ty_sub
553 ty_super;
554 let (env, ety_super) = Env.expand_internal_type env ty_super in
555 let (env, ety_sub) = Env.expand_internal_type env ty_sub in
556 let fail_with_suffix suffix =
557 let r_super = reason ety_super in
558 let r_sub = reason ety_sub in
559 let ty_super_descr = describe_ty_super env ety_super in
560 let ty_sub_descr =
561 Markdown_lite.md_codify
562 (Typing_print.with_blank_tyvars (fun () ->
563 Typing_print.full_strip_ns_i env ety_sub))
565 let (ty_super_descr, ty_sub_descr) =
566 if String.equal ty_super_descr ty_sub_descr then
567 ( "exactly the type " ^ ty_super_descr,
568 "the nonexact type " ^ ty_sub_descr )
569 else
570 (ty_super_descr, ty_sub_descr)
572 let left = Reason.to_string ("Expected " ^ ty_super_descr) r_super in
573 let right = Reason.to_string ("But got " ^ ty_sub_descr) r_sub @ suffix in
574 match (r_super, r_sub) with
575 | (Reason.Rcstr_on_generics (p, tparam), _)
576 | (_, Reason.Rcstr_on_generics (p, tparam)) ->
577 Errors.violated_constraint p tparam left right subtype_env.on_error
578 | _ ->
579 let claim = List.hd_exn left in
580 let reasons = List.tl_exn left @ right in
581 subtype_env.on_error claim reasons
583 let fail () = fail_with_suffix [] in
584 let ( ||| ) = ( ||| ) ~fail in
585 (* We *know* that the assertion is unsatisfiable *)
586 let invalid_env env = invalid ~fail env in
587 let invalid_env_with env f = invalid ~fail:f env in
588 (* We don't know whether the assertion is valid or not *)
589 let default env = (env, TL.IsSubtype (ety_sub, ety_super)) in
590 let default_subtype env =
591 default_subtype ~subtype_env ~this_ty ~fail env ety_sub ety_super
593 match ety_super with
594 (* First deal with internal constraint types *)
595 | ConstraintType cty_super ->
596 let using_new_method_call_inference =
597 TypecheckerOptions.method_call_inference (Env.get_tcopt env)
599 begin
600 match deref_constraint_type cty_super with
601 | (_, TCintersection (lty, cty)) ->
602 (match ety_sub with
603 | LoclType t when is_union t -> default_subtype env
604 | ConstraintType t when is_constraint_type_union t ->
605 default_subtype env
606 | _ ->
608 |> simplify_subtype_i ~subtype_env ty_sub (LoclType lty)
609 &&& simplify_subtype_i ~subtype_env ty_sub (ConstraintType cty))
610 | (_, TCunion (maybe_null, maybe_has_member))
611 when using_new_method_call_inference
612 && is_has_member maybe_has_member
614 let (_, maybe_null) = Env.expand_type env maybe_null in
615 is_prim Aast.Tnull maybe_null ->
616 (* `LHS <: Thas_member(...) | null` is morally a null-safe object access *)
617 let (env, null_ty) = Env.expand_type env maybe_null in
618 let r_null = get_reason null_ty in
619 let (r, has_member_ty) = deref_constraint_type maybe_has_member in
620 (match has_member_ty with
621 | Thas_member has_member_ty ->
622 simplify_subtype_has_member
623 ~subtype_env
624 ~this_ty
625 ~nullsafe:r_null
626 ~fail
627 ety_sub
628 (r, has_member_ty)
630 | _ -> invalid_env env (* Not possible due to guard in parent match *))
631 | (_, TCunion (lty_super, cty_super)) ->
632 (match ety_sub with
633 | ConstraintType cty when is_constraint_type_union cty ->
634 default_subtype env
635 | ConstraintType _ ->
637 |> simplify_subtype_i ~subtype_env ty_sub (LoclType lty_super)
638 ||| simplify_subtype_i ~subtype_env ty_sub (ConstraintType cty_super)
639 ||| default_subtype
640 | LoclType lty ->
641 (match deref lty with
642 | (r, Toption ty) ->
643 let ty_null = MakeType.null r in
644 if_unsat
645 invalid_env
646 (simplify_subtype_i
647 ~subtype_env
648 ~this_ty
649 (LoclType ty_null)
650 ty_super
651 env)
652 &&& simplify_subtype_i ~subtype_env ~this_ty (LoclType ty) ty_super
653 | (_, (Tintersection _ | Tunion _ | Terr | Tvar _)) ->
654 default_subtype env
655 | _ ->
657 |> simplify_subtype_i ~subtype_env ty_sub (LoclType lty_super)
658 ||| simplify_subtype_i
659 ~subtype_env
660 ty_sub
661 (ConstraintType cty_super)
662 ||| default_subtype))
663 | (r_super, Tdestructure { d_required; d_optional; d_variadic; d_kind })
665 (* List destructuring *)
666 let destructure_array t env =
667 (* If this is a splat, there must be a variadic box to receive the elements
668 * but for list(...) destructuring this is not required. Example:
670 * function f(int $i): void {}
671 * function g(vec<int> $v): void {
672 * list($a) = $v; // ok (but may throw)
673 * f(...$v); // error
674 * } *)
675 let fpos =
676 match r_super with
677 | Reason.Runpack_param (_, fpos, _) -> fpos
678 | _ -> Reason.to_pos r_super
680 match (d_kind, d_required, d_variadic) with
681 | (SplatUnpack, _ :: _, _) ->
682 (* return the env so as not to discard the type variable that might
683 have been created for the Traversable type created below. *)
684 invalid_env_with env (fun () ->
685 Errors.unpack_array_required_argument
686 (Reason.to_pos r_super)
687 fpos
688 subtype_env.on_error)
689 | (SplatUnpack, [], None) ->
690 invalid_env_with env (fun () ->
691 Errors.unpack_array_variadic_argument
692 (Reason.to_pos r_super)
693 fpos
694 subtype_env.on_error)
695 | (SplatUnpack, [], Some _)
696 | (ListDestructure, _, _) ->
697 List.fold d_required ~init:(env, TL.valid) ~f:(fun res ty_dest ->
698 res &&& simplify_subtype ~subtype_env ~this_ty t ty_dest)
699 &&& fun env ->
700 List.fold d_optional ~init:(env, TL.valid) ~f:(fun res ty_dest ->
701 res &&& simplify_subtype ~subtype_env ~this_ty t ty_dest)
702 &&& fun env ->
703 Option.value_map ~default:(env, TL.valid) d_variadic ~f:(fun vty ->
704 simplify_subtype ~subtype_env ~this_ty t vty env)
707 let destructure_tuple r ts env =
708 (* First fill the required elements. If there are insufficient elements, an error is reported.
709 * Fill as many of the optional elements as possible, and the remainder are unioned into the
710 * variadic element. Example:
712 * (float, bool, string, int) <: Tdestructure(#1, opt#2, ...#3) =>
713 * float <: #1 /\ bool <: #2 /\ string <: #3 /\ int <: #3
715 * (float, bool) <: Tdestructure(#1, #2, opt#3) =>
716 * float <: #1 /\ bool <: #2
718 let len_ts = List.length ts in
719 let len_required = List.length d_required in
720 let arity_error f =
721 let (epos, fpos, prefix) =
722 match r_super with
723 | Reason.Runpack_param (epos, fpos, c) -> (epos, fpos, c)
724 | _ -> (Reason.to_pos r_super, Reason.to_pos r, 0)
726 invalid_env_with env (fun () ->
728 (prefix + len_required)
729 (prefix + len_ts)
730 epos
731 fpos
732 (Some subtype_env.on_error))
734 if len_ts < len_required then
735 arity_error Errors.typing_too_few_args
736 else
737 let len_optional = List.length d_optional in
738 let (ts_required, remain) = List.split_n ts len_required in
739 let (ts_optional, ts_variadic) = List.split_n remain len_optional in
740 List.fold2_exn
741 ts_required
742 d_required
743 ~init:(env, TL.valid)
744 ~f:(fun res ty ty_dest ->
745 res &&& simplify_subtype ~subtype_env ~this_ty ty ty_dest)
746 &&& fun env ->
747 let len_ts_opt = List.length ts_optional in
748 let d_optional_part =
749 if len_ts_opt < len_optional then
750 List.take d_optional len_ts_opt
751 else
752 d_optional
754 List.fold2_exn
755 ts_optional
756 d_optional_part
757 ~init:(env, TL.valid)
758 ~f:(fun res ty ty_dest ->
759 res &&& simplify_subtype ~subtype_env ~this_ty ty ty_dest)
760 &&& fun env ->
761 match (ts_variadic, d_variadic) with
762 | (vars, Some vty) ->
763 List.fold vars ~init:(env, TL.valid) ~f:(fun res ty ->
764 res &&& simplify_subtype ~subtype_env ~this_ty ty vty)
765 | ([], None) -> valid env
766 | (_, None) ->
767 (* Elements remain but we have nowhere to put them *)
768 arity_error Errors.typing_too_many_args
771 begin
772 match ety_sub with
773 | ConstraintType _ -> default_subtype env
774 | LoclType ty_sub ->
775 (match deref ty_sub with
776 | (r, Ttuple tyl) -> env |> destructure_tuple r tyl
777 | (r, Tclass ((_, x), _, tyl))
778 when String.equal x SN.Collections.cPair ->
779 env |> destructure_tuple r tyl
780 | (_, Tclass ((_, x), _, [elt_type]))
781 when String.equal x SN.Collections.cVector
782 || String.equal x SN.Collections.cImmVector
783 || String.equal x SN.Collections.cVec
784 || String.equal x SN.Collections.cConstVector ->
785 env |> destructure_array elt_type
786 | (_, Tvarray elt_type) -> env |> destructure_array elt_type
787 | (_, Tdynamic) -> env |> destructure_array ty_sub
788 (* TODO: should remove these any cases *)
789 | (r, Tany _) ->
790 let any = mk (r, Typing_defs.make_tany ()) in
791 env |> destructure_array any
792 | (_, (Tunion _ | Tintersection _ | Tgeneric _ | Tvar _)) ->
793 (* TODO(T69551141) handle type arguments of Tgeneric? *)
794 default_subtype env
795 | _ ->
796 begin
797 match d_kind with
798 | SplatUnpack ->
799 (* Allow splatting of arbitrary Traversables *)
800 let (env, ty_inner) =
801 Env.fresh_type env (Reason.to_pos r_super)
803 let traversable = MakeType.traversable r_super ty_inner in
805 |> simplify_subtype ~subtype_env ~this_ty ty_sub traversable
806 &&& destructure_array ty_inner
807 | ListDestructure ->
808 let ty_sub_descr =
809 Typing_print.with_blank_tyvars (fun () ->
810 Typing_print.full_strip_ns env ty_sub)
812 default_subtype env
813 |> if_unsat @@ fun env ->
814 invalid_env_with env (fun () ->
815 Errors.invalid_destructure
816 (Reason.to_pos r_super)
817 (get_pos ty_sub)
818 ty_sub_descr
819 subtype_env.on_error)
820 end)
822 | (r, Thas_member has_member_ty) ->
823 simplify_subtype_has_member
824 ~subtype_env
825 ~this_ty
826 ~fail
827 ety_sub
828 (r, has_member_ty)
831 (* Next deal with all locl types *)
832 | LoclType ty_super ->
833 (match deref ty_super with
834 | (_, Terr) ->
835 (match ety_sub with
836 | ConstraintType cty when is_constraint_type_union cty ->
837 default_subtype env
838 | ConstraintType _ ->
839 if subtype_env.no_top_bottom then
840 default env
841 else
842 valid env
843 | LoclType lty ->
844 (match deref lty with
845 | (_, Tunion _) -> default_subtype env
846 | (_, Terr) -> valid env
847 | _ ->
848 if subtype_env.no_top_bottom then
849 default env
850 else
851 valid env))
852 | (_, Tvar var_super) ->
853 (match ety_sub with
854 | ConstraintType cty when is_constraint_type_union cty ->
855 default_subtype env
856 | ConstraintType _ -> default env
857 | LoclType ty_sub ->
858 (match deref ty_sub with
859 | (_, (Tunion _ | Terr)) -> default_subtype env
860 | (_, Tdynamic) when subtype_env.treat_dynamic_as_bottom ->
861 default_subtype env
862 (* We want to treat nullable as a union with the same rule as above.
863 * This is only needed for Tvar on right; other cases are dealt with specially as
864 * derived rules.
866 | (r, Toption t) ->
867 let (env, t) = Env.expand_type env t in
868 (match get_node t with
869 (* We special case on `mixed <: Tvar _`, adding the entire `mixed` type
870 as a lower bound. This enables clearer error messages when upper bounds
871 are added to the type variable: transitive closure picks up the
872 entire `mixed` type, and not separately consider `null` and `nonnull` *)
873 | Tnonnull -> default env
874 | _ ->
875 let ty_null = MakeType.null r in
877 |> simplify_subtype ~subtype_env ~this_ty t ty_super
878 &&& simplify_subtype ~subtype_env ~this_ty ty_null ty_super)
879 | (_, Tvar var_sub) when Ident.equal var_sub var_super -> valid env
880 | _ when subtype_env.treat_dynamic_as_bottom ->
881 (env, TL.Coerce (ty_sub, ty_super))
882 | _ -> default env))
883 | (_, Tintersection tyl) ->
884 (match ety_sub with
885 | ConstraintType cty when is_constraint_type_union cty ->
886 default_subtype env
887 | LoclType lty when is_union lty -> default_subtype env
888 (* t <: (t1 & ... & tn)
889 * if and only if
890 * t <: t1 /\ ... /\ t <: tn
892 | _ ->
893 List.fold_left tyl ~init:(env, TL.valid) ~f:(fun res ty_super ->
894 let ty_super = LoclType ty_super in
895 res &&& simplify_subtype_i ~subtype_env ~this_ty ty_sub ty_super))
896 (* Empty union encodes the bottom type nothing *)
897 | (_, Tunion []) -> default_subtype env
898 (* ty_sub <: union{ty_super'} iff ty_sub <: ty_super' *)
899 | (_, Tunion [ty_super']) ->
900 simplify_subtype_i ~subtype_env ~this_ty ty_sub (LoclType ty_super') env
901 | (_, Tunion (_ :: _ as tyl_super)) ->
902 let simplify_sub_union env ty_sub tyl_super =
903 (* It's sound to reduce t <: t1 | t2 to (t <: t1) || (t <: t2). But
904 * not complete e.g. consider (t1 | t3) <: (t1 | t2) | (t2 | t3).
905 * But we deal with unions on the left first (see case above), so this
906 * particular situation won't arise.
907 * TODO: identify under what circumstances this reduction is complete.
909 let rec try_each tys env =
910 match tys with
911 | [] ->
912 (match ty_sub with
913 | LoclType lty ->
914 begin
915 match get_node lty with
916 | Tnewtype _
917 | Tdependent _
918 | Tgeneric _ ->
919 default_subtype env
920 | _ -> invalid_env env
922 | _ -> invalid_env env)
923 | ty :: tys ->
924 let ty = LoclType ty in
926 |> simplify_subtype_i ~subtype_env ~this_ty ty_sub ty
927 ||| try_each tys
929 try_each tyl_super env
931 (match ety_sub with
932 | ConstraintType cty when is_constraint_type_union cty ->
933 default_subtype env
934 | ConstraintType _ -> simplify_sub_union env ty_sub tyl_super
935 | LoclType lty_sub ->
936 (match deref lty_sub with
937 | (_, (Tunion _ | Terr | Tvar _)) -> default_subtype env
938 | (_, Tgeneric _) when Option.is_none subtype_env.seen_generic_params ->
939 default_subtype env
940 (* Num is not atomic: it is equivalent to int|float. The rule below relies
941 * on ty_sub not being a union e.g. consider num <: arraykey | float, so
942 * we break out num first.
944 | (r, Tprim Nast.Tnum) ->
945 let ty_float = MakeType.float r and ty_int = MakeType.int r in
947 |> simplify_subtype ~subtype_env ~this_ty ty_float ty_super
948 &&& simplify_subtype ~subtype_env ~this_ty ty_int ty_super
949 (* Likewise, reduce nullable on left to a union *)
950 | (r, Toption ty) ->
951 let ty_null = MakeType.null r in
952 if_unsat
953 invalid_env
954 (simplify_subtype_i
955 ~subtype_env
956 ~this_ty
957 (LoclType ty_null)
958 ety_super
959 env)
960 &&& simplify_subtype_i ~subtype_env ~this_ty (LoclType ty) ety_super
961 | (_, Tintersection tyl)
962 when let (_, non_ty_opt, _) = find_type_with_exact_negation env tyl in
963 Option.is_some non_ty_opt ->
964 default_subtype env
965 | (_, Tintersection tyl_sub) ->
966 let simplify_super_intersection env tyl_sub ty_super =
967 (* It's sound to reduce t1 & t2 <: t to (t1 <: t) || (t2 <: t), but
968 * not complete.
970 List.fold_left
971 tyl_sub
972 ~init:(env, TL.invalid ~fail)
973 ~f:(fun res ty_sub ->
974 let ty_sub = LoclType ty_sub in
975 res ||| simplify_subtype_i ~subtype_env ~this_ty ty_sub ty_super)
977 (* Heuristicky logic to decide whether to "break" the intersection
978 or the union first, based on observing that the following cases often occur:
979 - A & B <: (A & B) | C
980 In which case we want to "break" the union on the right first
981 in order to have the following recursive calls :
982 A & B <: A & B
983 A & B <: C
984 - A & (B | C) <: B | C
985 In which case we want to "break" the intersection on the left first
986 in order to have the following recursive calls:
987 A <: B | C
988 B | C <: B | C
990 if List.exists tyl_super ~f:(Typing_utils.is_tintersection env) then
991 simplify_sub_union env ty_sub tyl_super
992 else if List.exists tyl_sub ~f:(Typing_utils.is_tunion env) then
993 simplify_super_intersection env tyl_sub (LoclType ty_super)
994 else
995 simplify_sub_union env ty_sub tyl_super
996 | _ -> simplify_sub_union env ty_sub tyl_super))
997 | (r_super, Toption arg_ty_super) ->
998 let (env, ety) = Env.expand_type env arg_ty_super in
999 (* Toption(Tnonnull) encodes mixed, which is our top type.
1000 * Everything subtypes mixed *)
1001 if is_nonnull ety then
1002 valid env
1003 else (
1004 match ety_sub with
1005 | ConstraintType _ -> default_subtype env
1006 | LoclType lty_sub ->
1007 (match (deref lty_sub, get_node ety) with
1008 | ((_, Tnewtype (name_sub, _, _)), Tnewtype (name_sup, _, _))
1009 when String.equal name_sup name_sub ->
1010 simplify_subtype ~subtype_env ~this_ty lty_sub arg_ty_super env
1011 (* A <: ?B iif A & nonnull <: B
1012 Only apply if B is a type variable or an intersection, to avoid oscillating
1013 forever between this case and the previous one. *)
1014 | ((_, Tintersection tyl), (Tintersection _ | Tvar _))
1015 when let (_, non_ty_opt, _) =
1016 find_type_with_exact_negation env tyl
1018 Option.is_none non_ty_opt ->
1019 let (env, ty_sub') =
1020 Inter.intersect_i env r_super ty_sub (MakeType.nonnull r_super)
1022 simplify_subtype_i ~subtype_env ty_sub' (LoclType arg_ty_super) env
1023 (* null is the type of null and is a subtype of any option type. *)
1024 | ((_, Tprim Nast.Tnull), _) -> valid env
1025 (* ?ty_sub' <: ?ty_super' iff ty_sub' <: ?ty_super'. Reasoning:
1026 * If ?ty_sub' <: ?ty_super', then from ty_sub' <: ?ty_sub' (widening) and transitivity
1027 * of <: it follows that ty_sub' <: ?ty_super'. Conversely, if ty_sub' <: ?ty_super', then
1028 * by covariance and idempotence of ?, we have ?ty_sub' <: ??ty_sub' <: ?ty_super'.
1029 * Therefore, this step preserves the set of solutions.
1031 | ((_, Toption ty_sub'), _) ->
1032 simplify_subtype ~subtype_env ~this_ty ty_sub' ty_super env
1033 (* We do not want to decompose Toption for these cases *)
1034 | ((_, (Tvar _ | Tunion _ | Tintersection _)), _) ->
1035 default_subtype env
1036 | ((_, Tgeneric _), _)
1037 when Option.is_none subtype_env.seen_generic_params ->
1038 (* TODO(T69551141) handle type arguments ? *)
1039 default_subtype env
1040 (* If t1 <: ?t2 and t1 is an abstract type constrained as t1',
1041 * then t1 <: t2 or t1' <: ?t2. The converse is obviously
1042 * true as well. We can fold the case where t1 is unconstrained
1043 * into the case analysis below.
1045 | ((_, (Tnewtype _ | Tdependent _ | Tgeneric _ | Tprim Nast.Tvoid)), _)
1047 (* TODO(T69551141) handle type arguments? *)
1049 |> simplify_subtype ~subtype_env ~this_ty lty_sub arg_ty_super
1050 ||| default_subtype
1051 (* If ty_sub <: ?ty_super' and ty_sub does not contain null then we
1052 * must also have ty_sub <: ty_super'. The converse follows by
1053 * widening and transitivity. Therefore, this step preserves the set
1054 * of solutions.
1056 | ((_, Tunapplied_alias _), _) ->
1057 Typing_defs.error_Tunapplied_alias_in_illegal_context ()
1058 | ( ( _,
1059 ( Tdynamic | Tprim _ | Tnonnull | Tfun _ | Ttuple _ | Tshape _
1060 | Tobject | Tclass _ | Tvarray _ | Tdarray _
1061 | Tvarray_or_darray _ | Tany _ | Terr | Taccess _ ) ),
1062 _ ) ->
1063 simplify_subtype ~subtype_env ~this_ty lty_sub arg_ty_super env)
1065 | (r_super, Tdependent (d_sup, bound_sup)) ->
1066 let (env, bound_sup) = Env.expand_type env bound_sup in
1067 (match ety_sub with
1068 | ConstraintType _ -> default_subtype env
1069 | LoclType ty_sub ->
1070 (match (deref ty_sub, get_node bound_sup) with
1071 | ((_, Tclass _), Tclass ((_, x), _, _))
1072 when is_final_and_not_contravariant env x ->
1073 (* For final class C, there is no difference between `this as X` and `X`,
1074 * and `expr<#n> as X` and `X`.
1075 * But we need to take care with contravariant classes, since we can't
1076 * statically guarantee their runtime type.
1078 simplify_subtype ~subtype_env ~this_ty ty_sub bound_sup env
1079 | ((r_sub, Tclass ((_, y), _, _)), Tclass (((_, x) as id), _, tyl_super))
1081 let fail =
1082 if String.equal x y then
1083 fun () ->
1084 let p = Reason.to_pos r_sub in
1085 fail_with_suffix (Errors.this_final id p)
1086 else
1087 fail
1090 let class_def = Env.get_class env x in
1091 (match (d_sup, class_def) with
1092 | (DTthis, Some class_ty) ->
1093 let tolerate_wrong_arity =
1094 not (Partial.should_check_error (Env.get_mode env) 4029)
1096 let tyl_super =
1097 if List.is_empty tyl_super && tolerate_wrong_arity then
1098 List.map (Cls.tparams class_ty) (fun _ ->
1099 mk (r_super, Typing_defs.make_tany ()))
1100 else
1101 tyl_super
1103 let ety_env =
1105 type_expansions = [];
1106 substs =
1107 TUtils.make_locl_subst_for_class_tparams class_ty tyl_super;
1108 this_ty = Option.value this_ty ~default:ty_super;
1109 from_class = None;
1110 on_error = subtype_env.on_error;
1111 quiet = true;
1114 let lower_bounds_super = Cls.lower_bounds_on_this class_ty in
1115 let rec try_constraints lower_bounds_super env =
1116 match lower_bounds_super with
1117 | [] -> invalid_env_with env fail
1118 | ty_super :: lower_bounds_super ->
1119 let (env, ty_super) = Phase.localize ~ety_env env ty_super in
1121 |> simplify_subtype ~subtype_env ~this_ty ty_sub ty_super
1122 ||| try_constraints lower_bounds_super
1124 try_constraints lower_bounds_super env
1125 | _ -> invalid_env_with env fail)
1126 | ((_, Tdependent (d_sub, bound_sub)), _) ->
1127 let this_ty = Option.first_some this_ty (Some ty_sub) in
1128 (* Dependent types are identical but bound might be different *)
1129 if equal_dependent_type d_sub d_sup then
1130 simplify_subtype ~subtype_env ~this_ty bound_sub bound_sup env
1131 else
1132 simplify_subtype ~subtype_env ~this_ty bound_sub ty_super env
1133 | _ -> default_subtype env))
1134 | (_, Taccess _) -> invalid_env env
1135 | (_, Tgeneric (name_super, tyargs_super)) ->
1136 (* TODO(T69551141) handle type arguments. Right now, only passing tyargs_super to
1137 Env.get_lower_bounds *)
1138 (match ety_sub with
1139 | ConstraintType _ -> default_subtype env
1140 (* If subtype and supertype are the same generic parameter, we're done *)
1141 | LoclType ty_sub ->
1142 (match get_node ty_sub with
1143 | Tgeneric (name_sub, tyargs_sub) when String.equal name_sub name_super
1145 if List.is_empty tyargs_super then
1146 valid env
1147 else
1148 (* TODO(T69931993) Type parameter env must carry variance information *)
1149 let variance_reifiedl =
1150 List.map tyargs_sub (fun _ -> (Ast_defs.Invariant, Aast.Erased))
1152 simplify_subtype_variance
1153 ~subtype_env
1154 name_sub
1155 variance_reifiedl
1156 tyargs_sub
1157 tyargs_super
1159 (* When decomposing subtypes for the purpose of adding bounds on generic
1160 * parameters to the context, (so seen_generic_params = None), leave
1161 * subtype so that the bounds get added *)
1162 | Tvar _
1163 | Tunion _
1164 | Terr ->
1165 default_subtype env
1166 | _ ->
1167 (match subtype_env.seen_generic_params with
1168 | None -> default env
1169 | Some seen ->
1170 (* If we've seen this type parameter before then we must have gone
1171 * round a cycle so we fail
1173 if SSet.mem name_super seen then
1174 invalid_env env
1175 else
1176 let subtype_env = add_seen_generic subtype_env name_super in
1177 (* Collect all the lower bounds ("super" constraints) on the
1178 * generic parameter, and check ty_sub against each of them in turn
1179 * until one of them succeeds *)
1180 let rec try_bounds tyl env =
1181 match tyl with
1182 | [] -> default_subtype env
1183 | ty :: tyl ->
1185 |> simplify_subtype ~subtype_env ~this_ty ty_sub ty
1186 ||| try_bounds tyl
1188 (* Turn error into a generic error about the type parameter *)
1190 |> try_bounds
1191 (Typing_set.elements
1192 (Env.get_lower_bounds env name_super tyargs_super))
1193 |> if_unsat invalid_env)))
1194 | (_, Tnonnull) ->
1195 (match ety_sub with
1196 | ConstraintType cty ->
1197 begin
1198 match deref_constraint_type cty with
1199 | (_, (Thas_member _ | Tdestructure _)) -> valid env
1200 | _ -> default_subtype env
1202 | LoclType lty ->
1203 (match deref lty with
1204 | ( _,
1205 ( Tprim
1206 Nast.(
1207 ( Tint | Tbool | Tfloat | Tstring | Tresource | Tnum
1208 | Tarraykey | Tnoreturn ))
1209 | Tnonnull | Tfun _ | Ttuple _ | Tshape _ | Tobject | Tclass _
1210 | Tvarray _ | Tdarray _ | Tvarray_or_darray _ | Taccess _ ) ) ->
1211 valid env
1212 | _ -> default_subtype env))
1213 | (_, Tdynamic)
1214 when TypecheckerOptions.enable_sound_dynamic env.genv.tcopt
1215 && subtype_env.allow_subtype_of_dynamic ->
1216 (match ety_sub with
1217 | ConstraintType _cty ->
1218 (* TODO *)
1219 default_subtype env
1220 | LoclType lty_sub ->
1221 (match deref lty_sub with
1222 | (_, Tdynamic)
1223 | (_, Tany _)
1224 | (_, Terr)
1225 | ( _,
1226 Tprim
1227 Aast_defs.(
1228 ( Tnull | Tint | Tbool | Tfloat | Tstring | Tnum | Tarraykey
1229 | Tvoid )) ) ->
1230 valid env
1231 | (_, Tprim Aast_defs.(Tresource | Tnoreturn))
1232 | (_, Tnonnull)
1233 | (_, Tfun _)
1234 | (_, Tshape (Open_shape, _))
1235 | (_, Tvar _)
1236 | (_, Tunapplied_alias _)
1237 | (_, Tnewtype _)
1238 | (_, Tdependent _)
1239 | (_, Tobject)
1240 | (_, Taccess _)
1241 | (_, Tunion _)
1242 | (_, Tintersection _)
1243 | (_, Tgeneric _) ->
1244 default_subtype env
1245 | (_, Toption ty)
1246 | (_, Tdarray (_, ty))
1247 | (_, Tvarray ty)
1248 | (_, Tvarray_or_darray (_, ty)) ->
1249 simplify_subtype ~subtype_env ty ty_super env
1250 | (_, Ttuple tyl) ->
1251 List.fold_left
1252 ~init:(env, TL.valid)
1253 ~f:(fun res ty_sub ->
1254 res &&& simplify_subtype ~subtype_env ty_sub ty_super)
1256 | (_, Tshape (Closed_shape, sftl)) ->
1257 List.fold_left
1258 ~init:(env, TL.valid)
1259 ~f:(fun res sft ->
1260 res &&& simplify_subtype ~subtype_env sft.sft_ty ty_super)
1261 (Nast.ShapeMap.values sftl)
1262 | (_, Tclass ((_, class_id), _, tyargs)) ->
1263 let class_def_sub = Typing_env.get_class env class_id in
1264 (match class_def_sub with
1265 | None ->
1266 (* This should have been caught already in the naming phase *)
1267 valid env
1268 | Some class_sub ->
1269 if Cls.get_implements_dynamic class_sub then
1270 valid env
1271 else if String.equal (Cls.name class_sub) SN.Collections.cVec then
1272 match tyargs with
1273 | [tyarg] -> simplify_subtype ~subtype_env tyarg ty_super env
1274 | _ ->
1275 (* This ill-formed type should have been caught earlier *)
1276 valid env
1277 else
1278 default_subtype env)))
1279 | (_, Tdynamic) ->
1280 (match ety_sub with
1281 | LoclType lty when is_dynamic lty -> valid env
1282 | ConstraintType _
1283 | LoclType _ ->
1284 default_subtype env)
1285 | (_, Tprim prim_ty) ->
1286 (match ety_sub with
1287 | ConstraintType _ -> default_subtype env
1288 | LoclType lty ->
1289 (match (deref lty, prim_ty) with
1290 | ((_, Tprim (Nast.Tint | Nast.Tfloat)), Nast.Tnum) -> valid env
1291 | ((_, Tprim (Nast.Tint | Nast.Tstring)), Nast.Tarraykey) -> valid env
1292 | ((_, Tprim prim_sub), _) when Aast.equal_tprim prim_sub prim_ty ->
1293 valid env
1294 | ((_, Toption arg_ty_sub), Nast.Tnull) ->
1295 simplify_subtype ~subtype_env ~this_ty arg_ty_sub ty_super env
1296 | (_, _) -> default_subtype env))
1297 | (_, Tobject) ->
1298 (match ety_sub with
1299 | ConstraintType _ -> default_subtype env
1300 (* Any class type is a subtype of object *)
1301 | LoclType lty ->
1302 (match get_node lty with
1303 | Tobject
1304 | Tclass _ ->
1305 valid env
1306 | _ -> default_subtype env))
1307 | (r_super, Tany _) ->
1308 (match ety_sub with
1309 | ConstraintType cty ->
1310 begin
1311 match deref_constraint_type cty with
1312 | (_, (TCunion _ | TCintersection _)) -> default_subtype env
1313 | _ -> valid env
1315 | LoclType ty_sub ->
1316 (match deref ty_sub with
1317 | (_, Tany _) -> valid env
1318 | (_, (Tunion _ | Tintersection _ | Tvar _)) -> default_subtype env
1319 | _ when subtype_env.no_top_bottom -> default env
1320 (* If ty_sub contains other types, e.g. C<T>, make this a subtype assertion on
1321 those inner types and `any`. For example transform the assertion
1322 C<D> <: Tany
1323 into
1324 C<D> <: C<Tany>
1325 which might become
1326 D <: Tany
1327 if say C is covariant.
1329 | _ ->
1330 let ty_super = anyfy env r_super ty_sub in
1331 simplify_subtype ~subtype_env ~this_ty ty_sub ty_super env))
1332 | (r_super, Tfun ft_super) ->
1333 (match ety_sub with
1334 | ConstraintType _ -> default_subtype env
1335 | LoclType lty ->
1336 (match deref lty with
1337 | (r_sub, Tfun ft_sub) ->
1338 simplify_subtype_funs
1339 ~subtype_env
1340 ~check_return:true
1341 r_sub
1342 ft_sub
1343 r_super
1344 ft_super
1346 | _ -> default_subtype env))
1347 | (_, Ttuple tyl_super) ->
1348 (match ety_sub with
1349 | ConstraintType _ -> default_subtype env
1350 (* (t1,...,tn) <: (u1,...,un) iff t1<:u1, ... , tn <: un *)
1351 | LoclType lty ->
1352 (match get_node lty with
1353 | Ttuple tyl_sub
1354 when Int.equal (List.length tyl_super) (List.length tyl_sub) ->
1355 wfold_left2
1356 (fun res ty_sub ty_super ->
1357 res &&& simplify_subtype ~subtype_env ty_sub ty_super)
1358 (env, TL.valid)
1359 tyl_sub
1360 tyl_super
1361 | _ -> default_subtype env))
1362 | (r_super, Tshape (shape_kind_super, fdm_super)) ->
1363 (match ety_sub with
1364 | ConstraintType _ -> default_subtype env
1365 | LoclType lty ->
1366 (match deref lty with
1367 | (r_sub, Tshape (shape_kind_sub, fdm_sub)) ->
1368 simplify_subtype_shape
1369 ~subtype_env
1370 ~env
1371 ~this_ty
1372 (r_sub, shape_kind_sub, fdm_sub)
1373 (r_super, shape_kind_super, fdm_super)
1374 | _ -> default_subtype env))
1375 | (_, (Tvarray _ | Tdarray _ | Tvarray_or_darray _)) ->
1376 (match ety_sub with
1377 | ConstraintType _ -> default_subtype env
1378 | LoclType lty ->
1379 (match (get_node lty, get_node ty_super) with
1380 | (Tvarray ty_sub, Tvarray ty_super) ->
1381 simplify_subtype ~subtype_env ~this_ty ty_sub ty_super env
1382 | ( Tvarray_or_darray (tk_sub, tv_sub),
1383 Tvarray_or_darray (tk_super, tv_super) )
1384 | (Tdarray (tk_sub, tv_sub), Tdarray (tk_super, tv_super))
1385 | (Tdarray (tk_sub, tv_sub), Tvarray_or_darray (tk_super, tv_super)) ->
1387 |> simplify_subtype ~subtype_env ~this_ty tk_sub tk_super
1388 &&& simplify_subtype ~subtype_env ~this_ty tv_sub tv_super
1389 | (Tvarray tv_sub, Tvarray_or_darray (tk_super, tv_super)) ->
1390 let pos = get_pos lty in
1391 let tk_sub = MakeType.int (Reason.Ridx_vector pos) in
1393 |> simplify_subtype ~subtype_env ~this_ty tk_sub tk_super
1394 &&& simplify_subtype ~subtype_env ~this_ty tv_sub tv_super
1395 | (Tvarray _, Tdarray _)
1396 | (Tdarray _, Tvarray _)
1397 | (Tvarray_or_darray _, Tdarray _)
1398 | (Tvarray_or_darray _, Tvarray _) ->
1399 invalid_env env
1400 | _ -> default_subtype env))
1401 | (_, Tnewtype (name_super, tyl_super, _)) ->
1402 (match ety_sub with
1403 | ConstraintType _ -> default_subtype env
1404 | LoclType lty ->
1405 (match deref lty with
1406 | (_, Tclass ((_, name_sub), _, _)) ->
1407 if String.equal name_sub name_super && Env.is_enum env name_super then
1408 valid env
1409 else
1410 default_subtype env
1411 | (_, Tnewtype (name_sub, tyl_sub, _))
1412 when String.equal name_sub name_super ->
1413 if List.is_empty tyl_sub then
1414 valid env
1415 else if Env.is_enum env name_super && Env.is_enum env name_sub then
1416 valid env
1417 else
1418 let td = Env.get_typedef env name_super in
1419 begin
1420 match td with
1421 | Some { td_tparams; _ } ->
1422 let variance_reifiedl =
1423 List.map td_tparams (fun t -> (t.tp_variance, t.tp_reified))
1425 simplify_subtype_variance
1426 ~subtype_env
1427 name_sub
1428 variance_reifiedl
1429 tyl_sub
1430 tyl_super
1432 | None -> invalid_env env
1434 | _ -> default_subtype env))
1435 | (_, Tunapplied_alias n_sup) ->
1436 (match ety_sub with
1437 | ConstraintType _ -> default_subtype env
1438 | LoclType lty ->
1439 (match deref lty with
1440 | (_, Tunapplied_alias n_sub) when String.equal n_sub n_sup -> valid env
1441 | _ -> default_subtype env))
1442 | (r_super, Tclass (((_, class_name) as x_super), exact_super, tyl_super))
1444 (match ety_sub with
1445 | ConstraintType _ -> default_subtype env
1446 | LoclType ty_sub ->
1447 (match deref ty_sub with
1448 | (_, Tnewtype (enum_name, _, _))
1449 when String.equal enum_name class_name
1450 && equal_exact exact_super Nonexact
1451 && Env.is_enum env enum_name ->
1452 valid env
1453 | (_, Tnewtype (cid, _, _))
1454 when String.equal class_name SN.Classes.cHH_BuiltinEnum
1455 && Env.is_enum env cid ->
1456 (match tyl_super with
1457 | [ty_super'] ->
1458 env |> simplify_subtype ~subtype_env ~this_ty ty_sub ty_super'
1459 | _ -> default_subtype env)
1460 | (_, Tnewtype (enum_name, _, _))
1461 when (String.equal enum_name class_name && Env.is_enum env enum_name)
1462 || String.equal class_name SN.Classes.cXHPChild ->
1463 valid env
1464 | ( _,
1465 ( Tvarray _ | Tdarray _ | Tvarray_or_darray _
1466 | Tprim Nast.(Tstring | Tarraykey | Tint | Tfloat | Tnum) ) )
1467 when String.equal class_name SN.Classes.cXHPChild
1468 && equal_exact exact_super Nonexact ->
1469 valid env
1470 | (_, Tprim Nast.Tstring)
1471 when String.equal class_name SN.Classes.cStringish
1472 && equal_exact exact_super Nonexact ->
1473 valid env
1474 (* Match what's done in unify for non-strict code *)
1475 | (_, Tobject)
1476 when not @@ Partial.should_check_error (Env.get_mode env) 4110 ->
1477 valid env
1478 | (r_sub, Tclass (x_sub, exact_sub, tyl_sub)) ->
1479 let (cid_super, cid_sub) = (snd x_super, snd x_sub) in
1480 let exact_match =
1481 match (exact_sub, exact_super) with
1482 | (Nonexact, Exact) -> false
1483 | (_, _) -> true
1485 if String.equal cid_super cid_sub then
1486 if List.is_empty tyl_sub && List.is_empty tyl_super && exact_match
1487 then
1488 valid env
1489 else
1490 (* This is side-effecting as it registers a dependency *)
1491 let class_def_sub = Env.get_class env cid_sub in
1492 (* If class is final then exactness is superfluous *)
1493 let is_final =
1494 match class_def_sub with
1495 | Some tc -> Cls.final tc
1496 | None -> false
1498 if not (exact_match || is_final) then
1499 invalid_env env
1500 else
1501 (* We handle the case where a generic A<T> is used as A *)
1502 let tyl_super =
1504 List.is_empty tyl_super
1505 && not (Partial.should_check_error (Env.get_mode env) 4101)
1506 then
1507 List.map tyl_sub (fun _ ->
1508 mk (r_super, Typing_defs.make_tany ()))
1509 else
1510 tyl_super
1512 let tyl_sub =
1514 List.is_empty tyl_sub
1515 && not (Partial.should_check_error (Env.get_mode env) 4101)
1516 then
1517 List.map tyl_super (fun _ ->
1518 mk (r_super, Typing_defs.make_tany ()))
1519 else
1520 tyl_sub
1522 if Int.( <> ) (List.length tyl_sub) (List.length tyl_super) then
1523 let n_sub = String_utils.soi (List.length tyl_sub) in
1524 let n_super = String_utils.soi (List.length tyl_super) in
1525 invalid_env_with env (fun () ->
1526 Errors.type_arity_mismatch
1527 (fst x_super)
1528 n_super
1529 (fst x_sub)
1530 n_sub
1531 subtype_env.on_error)
1532 else
1533 let variance_reifiedl =
1534 if List.is_empty tyl_sub then
1536 else
1537 match class_def_sub with
1538 | None ->
1539 List.map tyl_sub (fun _ ->
1540 (Ast_defs.Invariant, Aast.Erased))
1541 | Some class_sub ->
1542 List.map (Cls.tparams class_sub) (fun t ->
1543 (t.tp_variance, t.tp_reified))
1545 (* C<t1, .., tn> <: C<u1, .., un> iff
1546 * t1 <:v1> u1 /\ ... /\ tn <:vn> un
1547 * where vi is the variance of the i'th generic parameter of C,
1548 * and <:v denotes the appropriate direction of subtyping for variance v
1550 simplify_subtype_variance
1551 ~subtype_env
1552 cid_sub
1553 variance_reifiedl
1554 tyl_sub
1555 tyl_super
1557 else if not exact_match then
1558 invalid_env env
1559 else
1560 let class_def_sub = Env.get_class env cid_sub in
1561 (match class_def_sub with
1562 | None ->
1563 (* This should have been caught already in the naming phase *)
1564 valid env
1565 | Some class_sub ->
1566 (* We handle the case where a generic A<T> is used as A *)
1567 let tyl_sub =
1569 List.is_empty tyl_sub
1570 && not (Partial.should_check_error (Env.get_mode env) 4029)
1571 then
1572 List.map (Cls.tparams class_sub) (fun _ ->
1573 mk (r_sub, Typing_defs.make_tany ()))
1574 else
1575 tyl_sub
1577 let ety_env =
1579 type_expansions = [];
1580 substs =
1581 TUtils.make_locl_subst_for_class_tparams class_sub tyl_sub;
1582 (* TODO: do we need this? *)
1583 this_ty = Option.value this_ty ~default:ty_sub;
1584 from_class = None;
1585 quiet = true;
1586 on_error = subtype_env.on_error;
1589 let up_obj = Cls.get_ancestor class_sub cid_super in
1590 (match up_obj with
1591 | Some up_obj ->
1592 let (env, up_obj) = Phase.localize ~ety_env env up_obj in
1593 simplify_subtype ~subtype_env ~this_ty up_obj ty_super env
1594 | None ->
1596 Ast_defs.(equal_class_kind (Cls.kind class_sub) Ctrait)
1597 || Ast_defs.(equal_class_kind (Cls.kind class_sub) Cinterface)
1598 then
1599 let rec try_upper_bounds_on_this up_objs env =
1600 match up_objs with
1601 | [] ->
1602 (* It's crucial that we don't lose updates to global_tpenv in env that were
1603 * introduced by PHase.localize. TODO: avoid this requirement *)
1604 invalid_env env
1605 | ub_obj_typ :: up_objs ->
1606 (* a trait is never the runtime type, but it can be used
1607 * as a constraint if it has requirements or where constraints
1608 * for its using classes *)
1609 let (env, ub_obj_typ) =
1610 Phase.localize ~ety_env env ub_obj_typ
1613 |> simplify_subtype
1614 ~subtype_env
1615 ~this_ty
1616 (mk (r_sub, get_node ub_obj_typ))
1617 ty_super
1618 ||| try_upper_bounds_on_this up_objs
1620 try_upper_bounds_on_this
1621 (Cls.upper_bounds_on_this class_sub)
1623 else
1624 invalid_env env))
1625 | (r_sub, (Tvarray tv | Tdarray (_, tv) | Tvarray_or_darray (_, tv))) ->
1626 (match (exact_super, tyl_super) with
1627 | (Nonexact, [tv_super])
1628 when String.equal class_name SN.Collections.cTraversable
1629 || String.equal class_name SN.Rx.cTraversable
1630 || String.equal class_name SN.Collections.cContainer ->
1631 (* vec<tv> <: Traversable<tv_super>
1632 * iff tv <: tv_super
1633 * Likewise for vec<tv> <: Container<tv_super>
1634 * and map<_,tv> <: Traversable<tv_super>
1635 * and map<_,tv> <: Container<tv_super>
1637 simplify_subtype ~subtype_env ~this_ty tv tv_super env
1638 | (Nonexact, [tk_super; tv_super])
1639 when String.equal class_name SN.Collections.cKeyedTraversable
1640 || String.equal class_name SN.Rx.cKeyedTraversable
1641 || String.equal class_name SN.Collections.cKeyedContainer
1642 || String.equal class_name SN.Collections.cAnyArray ->
1643 (match get_node ty_sub with
1644 | Tvarray _ ->
1646 |> simplify_subtype
1647 ~subtype_env
1648 ~this_ty
1649 (MakeType.int r_sub)
1650 tk_super
1651 &&& simplify_subtype ~subtype_env ~this_ty tv tv_super
1652 | Tvarray_or_darray (tk, _)
1653 | Tdarray (tk, _) ->
1655 |> simplify_subtype ~subtype_env ~this_ty tk tk_super
1656 &&& simplify_subtype ~subtype_env ~this_ty tv tv_super
1657 | _ -> default_subtype env)
1658 | (Nonexact, [])
1659 when String.equal class_name SN.Collections.cKeyedTraversable
1660 || String.equal class_name SN.Rx.cKeyedTraversable
1661 || String.equal class_name SN.Collections.cKeyedContainer
1662 || String.equal class_name SN.Collections.cAnyArray ->
1663 (* All arrays are subtypes of the untyped KeyedContainer / Traversables *)
1664 valid env
1665 | (_, _) -> default_subtype env)
1666 | _ -> default_subtype env)))
1668 and simplify_subtype_shape
1669 ~(subtype_env : subtype_env)
1670 ~(env : env)
1671 ~(this_ty : locl_ty option)
1672 (r_sub, shape_kind_sub, fdm_sub)
1673 (r_super, shape_kind_super, fdm_super) =
1675 Shape projection for shape type `s` and field `f` (`s |_ f`) is defined as:
1676 - if `f` appears in `s` as `f => ty` then `s |_ f` = `Required ty`
1677 - if `f` appears in `s` as `?f => ty` then `s |_ f` = `Optional ty`
1678 - if `f` does not appear in `s` and `s` is closed, then `s |_ f` = `Absent`
1679 - if `f` does not appear in `s` and `s` is open, then `s |_ f` = `Optional mixed`
1681 EXCEPT
1682 - `?f => nothing` should be ignored, and treated as `Absent`.
1683 Such a field cannot be given a value, and so is effectively not present.
1685 let shape_projection field_name shape_kind shape_map r =
1686 match ShapeMap.find_opt field_name shape_map with
1687 | Some { sft_ty; sft_optional } ->
1688 begin
1689 match (deref sft_ty, sft_optional) with
1690 | ((_, Tunion []), true) -> `Absent
1691 | (_, true) -> `Optional sft_ty
1692 | (_, false) -> `Required sft_ty
1694 | None ->
1695 begin
1696 match shape_kind with
1697 | Open_shape ->
1698 let printable_name =
1699 TUtils.get_printable_shape_field_name field_name
1701 let mixed_ty =
1702 MakeType.mixed
1703 (Reason.Rmissing_optional_field (Reason.to_pos r, printable_name))
1705 `Optional mixed_ty
1706 | Closed_shape -> `Absent
1710 For two particular projections `p1` and `p2`, `p1` <: `p2` iff:
1711 - `p1` = `Required ty1`, `p2` = `Required ty2`, and `ty1` <: `ty2`
1712 - `p1` = `Required ty1`, `p2` = `Optional ty2`, and `ty1` <: `ty2`
1713 - `p1` = `Optional ty1`, `p2` = `Optional ty2`, and `ty1` <: `ty2`
1714 - `p1` = `Absent`, `p2` = `Optional ty2`
1715 - `p1` = `Absent`, `p2` = `Absent`
1716 We therefore need to handle all other cases appropriately.
1718 let simplify_subtype_shape_projection
1719 (r_sub, proj_sub) (r_super, proj_super) field_name res =
1720 let printable_name = TUtils.get_printable_shape_field_name field_name in
1721 match (proj_sub, proj_super) with
1722 (***** "Successful" cases - 5 / 9 total cases *****)
1723 | (`Required sub_ty, `Required super_ty)
1724 | (`Required sub_ty, `Optional super_ty)
1725 | (`Optional sub_ty, `Optional super_ty) ->
1726 res &&& simplify_subtype ~subtype_env ~this_ty sub_ty super_ty
1727 | (`Absent, `Optional _)
1728 | (`Absent, `Absent) ->
1730 (***** Error cases - 4 / 9 total cases *****)
1731 | (`Required _, `Absent)
1732 | (`Optional _, `Absent) ->
1734 |> with_error (fun () ->
1735 Errors.missing_field
1736 (Reason.to_pos r_super)
1737 (Reason.to_pos r_sub)
1738 printable_name
1739 subtype_env.on_error)
1740 | (`Optional _, `Required _) ->
1742 |> with_error (fun () ->
1743 Errors.required_field_is_optional
1744 (Reason.to_pos r_sub)
1745 (Reason.to_pos r_super)
1746 printable_name
1747 subtype_env.on_error)
1748 | (`Absent, `Required _) ->
1750 |> with_error (fun () ->
1751 Errors.missing_field
1752 (Reason.to_pos r_sub)
1753 (Reason.to_pos r_super)
1754 printable_name
1755 subtype_env.on_error)
1757 (* Helper function to project out a field and then simplify subtype *)
1758 let shape_project_and_simplify_subtype
1759 (r_sub, shape_kind_sub, shape_map_sub)
1760 (r_super, shape_kind_super, shape_map_super)
1761 field_name
1762 res =
1763 let proj_sub =
1764 shape_projection field_name shape_kind_sub shape_map_sub r_sub
1766 let proj_super =
1767 shape_projection field_name shape_kind_super shape_map_super r_super
1769 simplify_subtype_shape_projection
1770 (r_sub, proj_sub)
1771 (r_super, proj_super)
1772 field_name
1775 match (shape_kind_sub, shape_kind_super) with
1776 (* An open shape cannot subtype a closed shape *)
1777 | (Open_shape, Closed_shape) ->
1778 invalid
1779 ~fail:(fun () ->
1780 Errors.shape_fields_unknown
1781 (Reason.to_pos r_sub)
1782 (Reason.to_pos r_super)
1783 subtype_env.on_error)
1785 (* Otherwise, all projections must subtype *)
1786 | _ ->
1787 ShapeSet.fold
1788 (shape_project_and_simplify_subtype
1789 (r_sub, shape_kind_sub, fdm_sub)
1790 (r_super, shape_kind_super, fdm_super))
1791 (ShapeSet.of_list (ShapeMap.keys fdm_sub @ ShapeMap.keys fdm_super))
1792 (env, TL.valid)
1794 and simplify_subtype_has_member
1795 ~subtype_env
1796 ~this_ty
1797 ~fail
1798 ?(nullsafe : Reason.t option)
1799 ty_sub
1800 (r, has_member_ty)
1801 env =
1802 let using_new_method_call_inference =
1803 TypecheckerOptions.method_call_inference (Env.get_tcopt env)
1805 let {
1806 hm_name = name;
1807 hm_type = member_ty;
1808 hm_class_id = class_id;
1809 hm_explicit_targs = explicit_targs;
1811 has_member_ty
1813 let is_method = Option.is_some explicit_targs in
1814 (* If `nullsafe` is `Some _`, we are allowing the object type on LHS to be nullable. *)
1815 let mk_maybe_nullable env ty =
1816 match nullsafe with
1817 | None -> (env, ty)
1818 | Some r_null ->
1819 let null_ty = MakeType.null r_null in
1820 Typing_union.union_i env r_null ty null_ty
1822 let (env, maybe_nullable_ty_super) =
1823 let ty_super = mk_constraint_type (r, Thas_member has_member_ty) in
1824 mk_maybe_nullable env (ConstraintType ty_super)
1827 log_subtype_i
1828 ~level:2
1829 ~this_ty
1830 ~function_name:"simplify_subtype_has_member"
1832 ty_sub
1833 maybe_nullable_ty_super;
1834 let (env, ety_sub) = Env.expand_internal_type env ty_sub in
1835 let default_subtype env =
1836 default_subtype
1837 ~subtype_env
1838 ~this_ty
1839 ~fail
1841 ety_sub
1842 maybe_nullable_ty_super
1844 match ety_sub with
1845 | ConstraintType cty ->
1846 (match deref_constraint_type cty with
1847 | ( _,
1848 Thas_member
1850 hm_name = name_sub;
1851 hm_type = ty_sub;
1852 hm_class_id = cid_sub;
1853 hm_explicit_targs = explicit_targs_sub;
1854 } ) ->
1856 let targ_equal (_, (_, hint1)) (_, (_, hint2)) =
1857 Aast_defs.equal_hint_ hint1 hint2
1859 String.equal (snd name_sub) (snd name)
1860 && class_id_equal cid_sub class_id
1861 && Option.equal
1862 (List.equal targ_equal)
1863 explicit_targs_sub
1864 explicit_targs
1865 then
1866 simplify_subtype ~subtype_env ~this_ty ty_sub member_ty env
1867 else
1868 invalid ~fail env
1869 | _ -> default_subtype env)
1870 | LoclType ty_sub ->
1871 (match deref ty_sub with
1872 | (_, (Tvar _ | Tunion _ | Terr)) -> default_subtype env
1873 | (r_null, Tprim Aast.Tnull) when using_new_method_call_inference ->
1874 if Option.is_some nullsafe then
1875 valid env
1876 else
1877 invalid env ~fail:(fun () ->
1878 Errors.null_member_read
1879 ~is_method
1880 (snd name)
1881 (fst name)
1882 (Reason.to_string "This can be null" r_null))
1883 | (r_option, Toption option_ty) when using_new_method_call_inference ->
1884 if Option.is_some nullsafe then
1885 simplify_subtype_has_member
1886 ~subtype_env
1887 ~this_ty
1888 ~fail
1889 ?nullsafe
1890 (LoclType option_ty)
1891 (r, has_member_ty)
1893 else
1894 let (env, option_ty) = Env.expand_type env option_ty in
1895 (match get_node option_ty with
1896 | Tnonnull ->
1897 invalid env ~fail:(fun () ->
1898 Errors.top_member_read
1899 ~is_method
1900 ~is_nullable:true
1901 (snd name)
1902 (fst name)
1903 (Typing_print.error env ty_sub)
1904 (Reason.to_pos r_option))
1905 | _ ->
1906 invalid env ~fail:(fun () ->
1907 Errors.null_member_read
1908 ~is_method
1909 (snd name)
1910 (fst name)
1911 (Reason.to_string "This can be null" r_option)))
1912 | (_, Tintersection tyl)
1913 when let (_, non_ty_opt, _) = find_type_with_exact_negation env tyl in
1914 Option.is_some non_ty_opt ->
1915 (* use default_subtype to perform: A & B <: C <=> A <: C | !B *)
1916 default_subtype env
1917 | (r_inter, Tintersection []) ->
1918 (* Tintersection [] = mixed *)
1919 invalid env ~fail:(fun () ->
1920 Errors.top_member_read
1921 ~is_method
1922 ~is_nullable:true
1923 (snd name)
1924 (fst name)
1925 (Typing_print.error env ty_sub)
1926 (Reason.to_pos r_inter))
1927 | (r_inter, Tintersection tyl) when using_new_method_call_inference ->
1928 let (env, tyl) = List.map_env ~f:Env.expand_type env tyl in
1929 let subtype_fresh_has_member_ty env ty_sub =
1930 let (env, fresh_tyvar) = Env.fresh_type env (get_pos member_ty) in
1931 let env = Env.set_tyvar_variance env fresh_tyvar in
1932 let fresh_has_member_ty =
1933 mk_constraint_type
1934 (r, Thas_member { has_member_ty with hm_type = fresh_tyvar })
1936 let (env, maybe_nullable_fresh_has_member_ty) =
1937 mk_maybe_nullable env (ConstraintType fresh_has_member_ty)
1939 let (env, succeeded) =
1940 sub_type_inner
1942 ~subtype_env
1943 ~this_ty
1944 (LoclType ty_sub)
1945 maybe_nullable_fresh_has_member_ty
1947 if succeeded then
1948 let env =
1949 match get_var fresh_tyvar with
1950 | Some var ->
1951 Typing_solver.solve_to_equal_bound_or_wrt_variance
1953 Reason.Rnone
1955 subtype_env.on_error
1956 | None -> env
1958 (env, Some fresh_tyvar)
1959 else
1960 (env, None)
1962 let (env, fresh_tyvar_opts) =
1963 TUtils.run_on_intersection env tyl ~f:subtype_fresh_has_member_ty
1965 let fresh_tyvars = List.filter_map ~f:Fn.id fresh_tyvar_opts in
1966 if List.is_empty fresh_tyvars then
1967 (* TUtils.run_on_intersection has already added errors - no need to add more *)
1968 invalid ~fail:(fun () -> ()) env
1969 else
1970 let (env, intersection_ty) =
1971 Inter.intersect_list env r_inter fresh_tyvars
1973 simplify_subtype ~subtype_env ~this_ty intersection_ty member_ty env
1974 | (_, Tnewtype (_, _, newtype_ty)) ->
1975 simplify_subtype_has_member
1976 ~subtype_env
1977 ~this_ty
1978 ~fail
1979 ?nullsafe
1980 (LoclType newtype_ty)
1981 (r, has_member_ty)
1983 (* TODO
1984 | (_, Tdependent _) ->
1985 | (_, Tgeneric _) ->
1987 | _ ->
1988 let explicit_targs =
1989 match explicit_targs with
1990 | None -> []
1991 | Some targs -> targs
1993 let (errors, (env, (obj_get_ty, _tal))) =
1994 Errors.do_ (fun () ->
1995 Typing_object_get.obj_get
1996 ~obj_pos:(Reason.to_pos r)
1997 ~is_method
1998 ~coerce_from_ty:None
1999 ~nullsafe
2000 ~explicit_targs
2002 ty_sub
2003 class_id
2004 name
2005 subtype_env.on_error)
2007 let prop =
2008 if Errors.is_empty errors then
2009 valid env
2010 else
2011 invalid env ~fail:(fun () -> Errors.merge_into_current errors)
2013 prop &&& simplify_subtype ~subtype_env ~this_ty obj_get_ty member_ty)
2015 and simplify_subtype_variance
2016 ~(subtype_env : subtype_env)
2017 (cid : string)
2018 (variance_reifiedl : (Ast_defs.variance * Aast.reify_kind) list)
2019 (children_tyl : locl_ty list)
2020 (super_tyl : locl_ty list) : env -> env * TL.subtype_prop =
2021 fun env ->
2022 let simplify_subtype reify_kind =
2023 (* When doing coercions we treat dynamic as a bottom type. This is generally
2024 correct, except for the case when the generic isn't erased. When a generic is
2025 reified it is enforced as if it is it's own separate class in the runtime. i.e.
2026 In the code:
2028 class Box<reify T> {}
2029 function box_int(): Box<int> { return new Box<~int>(); }
2031 If is enforced like:
2032 class Box<reify T> {}
2033 class Box_int extends Box<int> {}
2034 class Box_like_int extends Box<~int> {}
2036 function box_int(): Box_int { return new Box_like_int(); }
2038 Thus we cannot push the like type to the outside of generic like we can
2039 we erased generics.
2042 let subtype_env =
2043 if not Aast.(equal_reify_kind reify_kind Erased) then
2044 { subtype_env with treat_dynamic_as_bottom = false }
2045 else
2046 subtype_env
2048 simplify_subtype ~subtype_env ~this_ty:None
2050 let simplify_subtype_variance = simplify_subtype_variance ~subtype_env in
2051 match (variance_reifiedl, children_tyl, super_tyl) with
2052 | ([], _, _)
2053 | (_, [], _)
2054 | (_, _, []) ->
2055 valid env
2056 | ( (variance, reify_kind) :: variance_reifiedl,
2057 child :: childrenl,
2058 super :: superl ) ->
2059 let simplify_subtype = simplify_subtype reify_kind in
2060 begin
2061 match variance with
2062 | Ast_defs.Covariant -> simplify_subtype child super env
2063 | Ast_defs.Contravariant ->
2064 let super =
2066 ( Reason.Rcontravariant_generic (get_reason super, cid),
2067 get_node super )
2069 simplify_subtype super child env
2070 | Ast_defs.Invariant ->
2071 let super' =
2072 mk (Reason.Rinvariant_generic (get_reason super, cid), get_node super)
2074 env |> simplify_subtype child super' &&& simplify_subtype super' child
2076 &&& simplify_subtype_variance cid variance_reifiedl childrenl superl
2078 and simplify_subtype_params
2079 ~(subtype_env : subtype_env)
2080 ?(is_method : bool = false)
2081 ?(check_params_reactivity = false)
2082 ?(check_params_mutability = false)
2083 ?(check_params_ifc = false)
2084 (subl : locl_fun_param list)
2085 (superl : locl_fun_param list)
2086 (variadic_sub_ty : locl_possibly_enforced_ty option)
2087 (variadic_super_ty : locl_possibly_enforced_ty option)
2088 env =
2089 let simplify_subtype_possibly_enforced =
2090 simplify_subtype_possibly_enforced ~subtype_env
2092 let simplify_subtype_params = simplify_subtype_params ~subtype_env in
2093 let simplify_subtype_params_with_variadic =
2094 simplify_subtype_params_with_variadic ~subtype_env
2096 let simplify_supertype_params_with_variadic =
2097 simplify_supertype_params_with_variadic ~subtype_env
2099 match (subl, superl) with
2100 (* When either list runs out, we still have to typecheck that
2101 the remaining portion sub/super types with the other's variadic.
2102 For example, if
2103 ChildClass {
2104 public function a(int $x = 0, string ... $args) // superl = [int], super_var = string
2106 overrides
2107 ParentClass {
2108 public function a(string ... $args) // subl = [], sub_var = string
2110 , there should be an error because the first argument will be checked against
2111 int, not string that is, ChildClass::a("hello") would crash,
2112 but ParentClass::a("hello") wouldn't.
2114 Similarly, if the other list is longer, aka
2115 ChildClass extends ParentClass {
2116 public function a(mixed ... $args) // superl = [], super_var = mixed
2118 overrides
2119 ParentClass {
2120 //subl = [string], sub_var = string
2121 public function a(string $x = 0, string ... $args)
2123 It should also check that string is a subtype of mixed.
2125 | ([], _) ->
2126 (match variadic_super_ty with
2127 | None -> valid env
2128 | Some ty -> simplify_supertype_params_with_variadic superl ty env)
2129 | (_, []) ->
2130 (match variadic_sub_ty with
2131 | None -> valid env
2132 | Some ty -> simplify_subtype_params_with_variadic subl ty env)
2133 | (sub :: subl, super :: superl) ->
2134 ( env
2135 |> begin
2136 if check_params_reactivity then
2137 simplify_subtype_fun_params_reactivity ~subtype_env sub super
2138 else
2139 valid
2142 if check_params_mutability then
2143 check_mutability
2144 ~is_receiver:false
2145 ~subtype_env
2146 sub.fp_pos
2147 (get_fp_mutability sub)
2148 super.fp_pos
2149 (get_fp_mutability super)
2150 else
2151 valid )
2152 &&& fun env ->
2153 let { fp_type = ty_sub; _ } = sub in
2154 let { fp_type = ty_super; _ } = super in
2155 (* Check that the calling conventions of the params are compatible. *)
2157 |> simplify_param_modes ~subtype_env sub super
2158 &&& simplify_param_accept_disposable ~subtype_env sub super
2159 &&& begin
2160 if check_params_ifc then
2161 simplify_param_ifc ~subtype_env sub super
2162 else
2163 valid
2165 &&& begin
2166 fun env ->
2167 match (get_fp_mode sub, get_fp_mode super) with
2168 | (FPinout, FPinout) ->
2169 (* Inout parameters are invariant wrt subtyping for function types. *)
2171 |> simplify_subtype_possibly_enforced ty_super ty_sub
2172 &&& simplify_subtype_possibly_enforced ty_sub ty_super
2173 | _ -> env |> simplify_subtype_possibly_enforced ty_sub ty_super
2175 &&& simplify_subtype_params
2176 ~is_method
2177 subl
2178 superl
2179 variadic_sub_ty
2180 variadic_super_ty
2182 and simplify_subtype_params_with_variadic
2183 ~(subtype_env : subtype_env)
2184 (subl : locl_fun_param list)
2185 (variadic_ty : locl_possibly_enforced_ty)
2186 env =
2187 let simplify_subtype_possibly_enforced =
2188 simplify_subtype_possibly_enforced ~subtype_env
2190 let simplify_subtype_params_with_variadic =
2191 simplify_subtype_params_with_variadic ~subtype_env
2193 match subl with
2194 | [] -> valid env
2195 | { fp_type = sub; _ } :: subl ->
2197 |> simplify_subtype_possibly_enforced sub variadic_ty
2198 &&& simplify_subtype_params_with_variadic subl variadic_ty
2200 and simplify_subtype_implicit_params
2201 ~subtype_env { capability = sub_cap } { capability = super_cap } env =
2202 if TypecheckerOptions.any_coeffects (Env.get_tcopt env) then
2203 let subtype_env =
2205 subtype_env with
2206 on_error =
2207 begin
2208 fun ?code:_ _ _ ->
2209 let expected = Typing_coeffects.get_type sub_cap in
2210 let got = Typing_coeffects.get_type super_cap in
2211 Errors.coeffect_subtyping_error
2212 (get_pos expected)
2213 (Typing_print.coeffects env expected)
2214 (get_pos got)
2215 (Typing_print.coeffects env got)
2216 subtype_env.on_error
2217 end;
2220 match (sub_cap, super_cap) with
2221 | (CapTy sub, CapTy super) -> simplify_subtype ~subtype_env sub super env
2222 | (CapTy sub, CapDefaults _p) ->
2223 let super = Typing_coeffects.get_type super_cap in
2224 simplify_subtype ~subtype_env sub super env
2225 | (CapDefaults _p, CapTy super) ->
2226 let sub = Typing_coeffects.get_type sub_cap in
2227 simplify_subtype ~subtype_env sub super env
2228 | (CapDefaults _p1, CapDefaults _p2) -> valid env
2229 else
2230 valid env
2232 and simplify_supertype_params_with_variadic
2233 ~(subtype_env : subtype_env)
2234 (superl : locl_fun_param list)
2235 (variadic_ty : locl_possibly_enforced_ty)
2236 env =
2237 let simplify_subtype_possibly_enforced =
2238 simplify_subtype_possibly_enforced ~subtype_env
2240 let simplify_supertype_params_with_variadic =
2241 simplify_supertype_params_with_variadic ~subtype_env
2243 match superl with
2244 | [] -> valid env
2245 | { fp_type = super; _ } :: superl ->
2247 |> simplify_subtype_possibly_enforced variadic_ty super
2248 &&& simplify_supertype_params_with_variadic superl variadic_ty
2250 and simplify_subtype_reactivity
2251 ~subtype_env
2252 ?(extra_info : reactivity_extra_info option)
2253 ?(is_call_site = false)
2254 p_sub
2255 (r_sub : reactivity)
2256 p_super
2257 (r_super : reactivity)
2258 (env : env) : env * TL.subtype_prop =
2259 let fail () =
2260 let msg_super =
2261 "This function is " ^ TUtils.reactivity_to_string env r_super ^ "."
2263 let msg_sub =
2264 "This function is " ^ TUtils.reactivity_to_string env r_sub ^ "."
2266 subtype_env.on_error (p_super, msg_super) [(p_sub, msg_sub)]
2268 let ( ||| ) = ( ||| ) ~fail in
2269 let invalid_env env = invalid ~fail env in
2270 let maybe_localize t =
2271 match t with
2272 | DeclTy t ->
2273 let ety_env = Phase.env_with_self env in
2274 let (_, t) = Phase.localize ~ety_env env t in
2276 | LoclTy t -> t
2278 let class_ty =
2279 Option.bind extra_info (fun { class_ty = cls; _ } ->
2280 Option.map cls ~f:maybe_localize)
2282 (* for method declarations check if condition type for r_super includes
2283 reactive method with a matching name. If yes - then it will act as a guarantee
2284 that derived class will have to redefine the method with a shape required
2285 by condition type (reactivity of redefined method must be subtype of reactivity
2286 of method in interface) *)
2287 let check_condition_type_has_matching_reactive_method env =
2288 (* function type TSub of method M with arbitrary reactivity in derive class
2289 can be subtype of conditionally reactive function type TSuper of method M
2290 defined in base class when condition type has reactive method M.
2291 interface Rx {
2292 <<__Rx>>
2293 public function f(): int;
2295 class A {
2296 <<__RxIfImplements(Rx::class)>>
2297 public function f(): int { ... }
2299 class B extends A {
2300 public function f(): int { ... }
2302 This should be OK because:
2303 - B does not implement Rx (B::f is not compatible with Rx::f) which means
2304 that calling ($b : B)->f() will not be treated as reactive
2305 - if one of subclasses of B will decide to implement B - they will be forced
2306 to redeclare f which now will shadow B::f. Note that B::f will still be
2307 accessible as parent::f() but will be treated as non-reactive call.
2309 match (r_super, extra_info) with
2310 | ( ( Pure (Some condition_type_super)
2311 | Reactive (Some condition_type_super)
2312 | Shallow (Some condition_type_super)
2313 | Local (Some condition_type_super) ),
2314 Some { method_info = Some (method_name, is_static); _ } ) ->
2315 let m =
2316 ConditionTypes.try_get_method_from_condition_type
2318 condition_type_super
2319 is_static
2320 method_name
2322 begin
2323 (* check that reactivity of interface method (effectively a promised
2324 reactivity of a method in derived class) is a subtype of r_super.
2325 NOTE: we check only for unconditional reactivity since conditional
2326 version does not seems to yield a lot and will requre implementing
2327 cycle detection for condition types *)
2328 match m with
2329 | Some { ce_type = (lazy ty); _ } ->
2330 begin
2331 match get_node ty with
2332 | Tfun
2334 ft_reactive =
2335 (Pure None | Reactive None | Shallow None | Local None) as
2338 } ->
2339 let extra_info =
2341 empty_extra_info with
2342 parent_class_ty = Some (DeclTy condition_type_super);
2345 simplify_subtype_reactivity
2346 ~subtype_env
2347 ~extra_info
2348 p_sub
2350 p_super
2351 r_super
2353 | _ -> invalid_env env
2355 | _ -> invalid_env env
2357 | _ -> invalid_env env
2359 let is_some_cipp_or_pure r =
2360 match r with
2361 | Pure _
2362 | CippRx ->
2363 true
2364 | Nonreactive -> false
2365 | _ -> not (any_reactive r)
2367 match (r_sub, r_super) with
2368 (* hardcode that cipp can't call noncipp and vice versa since we want to
2369 allow subtyping to aid in testing, but let normal calling checks handle
2370 cipp/pure v cipp/pure *)
2371 | (Cipp _, _) when is_call_site && not (is_some_cipp_or_pure r_super) ->
2372 invalid_env env
2373 | (_, Cipp _) when is_call_site && not (is_some_cipp_or_pure r_sub) ->
2374 invalid_env env
2375 (* anything is a subtype of nonreactive functions *)
2376 | (_, Nonreactive) -> valid env
2377 (* to compare two maybe reactive values we need to unwrap them *)
2378 | (MaybeReactive sub, MaybeReactive super) ->
2379 simplify_subtype_reactivity
2380 ~subtype_env
2381 ?extra_info
2382 ~is_call_site
2383 p_sub
2385 p_super
2386 super
2388 (* for explicit checks at callsites implicitly unwrap maybereactive value:
2389 function f(<<__AtMostRxAsFunc>> F $f)
2390 f(<<__RxLocal>> () ==> {... })
2391 here parameter will be maybereactive and argument - rxlocal
2393 | (sub, MaybeReactive super) when is_call_site ->
2394 simplify_subtype_reactivity
2395 ~subtype_env
2396 ?extra_info
2397 ~is_call_site
2398 p_sub
2400 p_super
2401 super
2403 (* if is_call_site is falst ignore maybereactive flavors.
2404 This usually happens during subtype checks for arguments and when target
2405 function is conditionally reactive we'll do the proper check
2406 in typing_reactivity.check_call. *)
2407 | (_, MaybeReactive _) when not is_call_site -> valid env
2408 (* ok:
2409 class A { function f((function(): int) $f) {} }
2410 class B extends A {
2411 <<__Rx>>
2412 function f(<<__AtMostRxAsFunc>> (function(): int) $f);
2414 reactivity for arguments is checked contravariantly *)
2415 | (_, RxVar None)
2416 (* ok:
2417 <<__Rx>>
2418 function f(<<__AtMostRxAsFunc>> (function(): int) $f) { return $f() } *)
2419 | (RxVar None, RxVar _) ->
2420 valid env
2421 | (RxVar (Some sub), RxVar (Some super))
2422 | (sub, RxVar (Some super)) ->
2423 simplify_subtype_reactivity
2424 ~subtype_env
2425 ?extra_info
2426 ~is_call_site
2427 p_sub
2429 p_super
2430 super
2432 | (RxVar _, _) -> invalid_env env
2433 | ( (Local cond_sub | Shallow cond_sub | Reactive cond_sub | Pure cond_sub),
2434 Local cond_super )
2435 | ((Shallow cond_sub | Reactive cond_sub | Pure cond_sub), Shallow cond_super)
2436 | ((Reactive cond_sub | Pure cond_sub), Reactive cond_super)
2437 | (Pure cond_sub, Pure cond_super) ->
2439 |> simplify_subtype_param_rx_if_impl
2440 ~subtype_env
2441 ~is_param:false
2442 p_sub
2443 cond_sub
2444 class_ty
2445 p_super
2446 cond_super
2447 ||| check_condition_type_has_matching_reactive_method
2448 (* call_site specific cases *)
2449 (* shallow can call into local *)
2450 | (Local cond_sub, Shallow cond_super) when is_call_site ->
2451 simplify_subtype_param_rx_if_impl
2452 ~subtype_env
2453 ~is_param:false
2454 p_sub
2455 cond_sub
2456 class_ty
2457 p_super
2458 cond_super
2460 (* local can call into non-reactive, but not for inheritance *)
2461 | (Nonreactive, Local _) when is_call_site -> valid env
2462 (* Cipp(Local) can call pure *)
2463 | (Pure _, (Cipp _ | CippLocal _ | CippRx)) -> valid env
2464 (* Cipp can call Cipp(Local) if the params match *)
2465 | (Cipp x, Cipp y) when Option.is_none x || Option.equal String.equal x y ->
2466 valid env
2467 | ((Cipp x | CippLocal x), CippLocal y)
2468 when Option.is_none x || Option.equal String.equal x y ->
2469 valid env
2470 (* Unsafe direction is only legal for callsites *)
2471 | (CippLocal x, Cipp y)
2472 when (is_call_site && Option.is_none x) || Option.equal String.equal x y ->
2473 valid env
2474 (* CippLocal can also call nonreactive *)
2475 | ( (Nonreactive | Reactive _ | Local _ | Shallow _ | MaybeReactive _),
2476 CippLocal _ )
2477 when is_call_site ->
2478 valid env
2479 (* Anything can call CippGlobal*)
2480 (* CippRx is the same as CippGlobal, but with reactivity constraints *)
2481 (* Nonreactive is covered from above*)
2482 | ( (CippGlobal | CippRx),
2483 ( Reactive _ | Local _ | Shallow _ | MaybeReactive _ | Cipp _
2484 | CippLocal _ | CippGlobal | CippRx | Pure _ ) ) ->
2485 valid env
2486 (* CippGlobal can (safely) call anything the following *)
2487 | ((Pure _ | Cipp _ | CippLocal _), CippGlobal) -> valid env
2488 (* CippGlobal can call anything (unsafe) *)
2489 | (_, CippGlobal) when is_call_site -> valid env
2490 | _ -> check_condition_type_has_matching_reactive_method env
2492 and should_check_fun_params_reactivity (ft_super : locl_fun_type) =
2493 any_reactive ft_super.ft_reactive
2495 (* checks condition described by OnlyRxIfImpl condition on parameter is met *)
2496 and simplify_subtype_param_rx_if_impl
2497 ~subtype_env
2498 ~is_param
2499 p_sub
2500 (cond_type_sub : decl_ty option)
2501 (declared_type_sub : locl_ty option)
2502 p_super
2503 (cond_type_super : decl_ty option)
2504 (env : env) : env * TL.subtype_prop =
2505 let cond_type_sub =
2506 Option.map cond_type_sub ~f:(ConditionTypes.localize_condition_type env)
2508 let cond_type_super =
2509 Option.map cond_type_super ~f:(ConditionTypes.localize_condition_type env)
2511 let invalid_env env =
2512 ( env,
2513 TL.invalid ~fail:(fun () ->
2514 Errors.rx_parameter_condition_mismatch
2515 SN.UserAttributes.uaOnlyRxIfImpl
2516 p_sub
2517 p_super
2518 subtype_env.on_error) )
2520 match (cond_type_sub, cond_type_super) with
2521 (* no condition types - do nothing *)
2522 | (None, None) -> valid env
2523 (* condition type is specified only for super - ok for receiver case (is_param is false)
2524 abstract class A {
2525 <<__RxLocal, __OnlyRxIfImpl(Rx1::class)>>
2526 public abstract function condlocalrx(): int;
2528 abstract class B extends A {
2529 // ok to override cond local with local (if condition is not met - method
2530 // in base class is non-reactive )
2531 <<__Override, __RxLocal>>
2532 public function condlocalrx(): int {
2533 return 1;
2536 for parameters we need to verify that declared type of sub is a subtype of
2537 conditional type for super. Here is an example where this is violated:
2539 interface A {}
2540 interface RxA {}
2542 class C1 {
2543 <<__Rx>>
2544 public function f(A $a): void {
2548 class C2 extends C1 {
2549 // ERROR: invariant f body is reactive iff $a instanceof RxA can be violated
2550 <<__Rx, __AtMostRxAsArgs>>
2551 public function f(<<__OnlyRxIfImpl(RxA::class)>>A $a): void {
2554 here declared type of sub is A
2555 and cond type of super is RxA
2557 | (None, Some _) when not is_param -> valid env
2558 | (None, Some cond_type_super) ->
2559 begin
2560 match declared_type_sub with
2561 | None -> invalid_env env
2562 | Some declared_type_sub ->
2563 simplify_subtype ~subtype_env declared_type_sub cond_type_super env
2565 (* condition types are set for both sub and super types: contravariant check
2566 interface A {}
2567 interface B extends A {}
2568 interface C extends B {}
2570 interface I1 {
2571 <<__Rx, __OnlyRxIfImpl(B::class)>>
2572 public function f(): void;
2573 <<__Rx>>
2574 public function g(<<__OnlyRxIfImpl(B::class)>> A $a): void;
2576 interface I2 extends I1 {
2577 // OK since condition in I1::f covers I2::f
2578 <<__Rx, __OnlyRxIfImpl(A::class)>>
2579 public function f(): void;
2580 // OK since condition in I1::g covers I2::g
2581 <<__Rx>>
2582 public function g(<<__OnlyRxIfImpl(A::class)>> A $a): void;
2584 interface I3 extends I1 {
2585 // Error since condition in I1::f is less strict that in I3::f
2586 <<__Rx, __OnlyRxIfImpl(C::class)>>
2587 public function f(): void;
2588 // Error since condition in I1::g is less strict that in I3::g
2589 <<__Rx>>
2590 public function g(<<__OnlyRxIfImpl(C::class)>> A $a): void;
2593 | (Some cond_type_sub, Some cond_type_super) ->
2594 if is_param then
2595 simplify_subtype ~subtype_env cond_type_sub cond_type_super env
2596 else
2597 simplify_subtype ~subtype_env cond_type_super cond_type_sub env
2598 (* condition type is set for super type, check if declared type of
2599 subtype is a subtype of condition type
2600 interface Rx {
2601 <<__Rx>>
2602 public function f(int $a): void;
2604 class A<T> {
2605 <<__Rx, __OnlyRxIfImpl(Rx::class)>>
2606 public function f(T $a): void {
2609 // B <: Rx so B::f is completely reactive
2610 class B extends A<int> implements Rx {
2611 } *)
2612 | (Some cond_type_sub, None) ->
2613 if is_param then
2614 valid env
2615 else begin
2616 match declared_type_sub with
2617 | None -> invalid_env env
2618 | Some declared_type_sub ->
2619 simplify_subtype ~subtype_env declared_type_sub cond_type_sub env
2622 (* checks reactivity conditions for function parameters *)
2623 and simplify_subtype_fun_params_reactivity
2624 ~subtype_env (p_sub : locl_fun_param) (p_super : locl_fun_param) env =
2625 match (p_sub.fp_rx_annotation, p_super.fp_rx_annotation) with
2626 (* no conditions on parameters - do nothing *)
2627 | (None, None) -> valid env
2628 (* both parameters are conditioned to be rx function - no need to check anything *)
2629 | (Some Param_rx_var, Some Param_rx_var) -> valid env
2630 | (None, Some Param_rx_var) ->
2631 (* parameter is conditionally reactive in supertype and missing condition
2632 in subtype - this is ok only if parameter in subtype is reactive
2633 <<__Rx>>
2634 function super((function(): int) $f);
2635 <<__Rx>>
2636 function sub(<<__AtMostRxAsFunc>> (function(): int) $f);
2637 We check if sub <: super. parameters are checked contravariantly
2638 so we need to verify that
2639 (function(): int) $f <: <<__AtMostRxAsFunc>> (function(): int) $f
2641 Suppose this is legal, then this will be allowed (in pseudo-code)
2643 function sub(<<__AtMostRxAsFunc>> (function(): int) $f) {
2644 $f(); // can call function here since it is conditionally reactive
2646 <<__Rx>>
2647 function g() {
2648 $f: super = sub;
2649 // invoke non-reactive code in reactive context which is bad
2650 $f(() ==> { echo 1; });
2653 It will be safe if parameter in super will be completely reactive,
2654 hence check below *)
2655 let (_, p_sub_type) = Env.expand_type env p_sub.fp_type.et_type in
2656 begin
2657 match get_node p_sub_type with
2658 | Tfun tfun when any_reactive tfun.ft_reactive -> valid env
2659 | Tfun _ ->
2660 ( env,
2661 TL.invalid ~fail:(fun () ->
2662 Errors.rx_parameter_condition_mismatch
2663 SN.UserAttributes.uaAtMostRxAsFunc
2664 p_sub.fp_pos
2665 p_super.fp_pos
2666 subtype_env.on_error) )
2667 (* parameter type is not function - error will be reported in different place *)
2668 | _ -> valid env
2670 | (cond_sub, cond_super) ->
2671 let cond_type_sub =
2672 match cond_sub with
2673 | Some (Param_rx_if_impl t) -> Some t
2674 | _ -> None
2676 let cond_type_super =
2677 match cond_super with
2678 | Some (Param_rx_if_impl t) -> Some t
2679 | _ -> None
2681 let subtype_env =
2683 subtype_env with
2684 on_error =
2685 (fun ?code:_ _ _ ->
2686 Errors.rx_parameter_condition_mismatch
2687 SN.UserAttributes.uaOnlyRxIfImpl
2688 p_sub.fp_pos
2689 p_super.fp_pos
2690 subtype_env.on_error);
2693 simplify_subtype_param_rx_if_impl
2694 ~subtype_env
2695 ~is_param:true
2696 p_sub.fp_pos
2697 cond_type_sub
2698 (Some p_sub.fp_type.et_type)
2699 p_super.fp_pos
2700 cond_type_super
2703 and simplify_param_modes ~subtype_env param1 param2 env =
2704 let { fp_pos = pos1; _ } = param1 in
2705 let { fp_pos = pos2; _ } = param2 in
2706 match (get_fp_mode param1, get_fp_mode param2) with
2707 | (FPnormal, FPnormal)
2708 | (FPinout, FPinout) ->
2709 valid env
2710 | (FPnormal, FPinout) ->
2711 invalid
2712 ~fail:(fun () -> Errors.inoutness_mismatch pos2 pos1 subtype_env.on_error)
2714 | (FPinout, FPnormal) ->
2715 invalid
2716 ~fail:(fun () -> Errors.inoutness_mismatch pos1 pos2 subtype_env.on_error)
2719 and simplify_param_accept_disposable ~subtype_env param1 param2 env =
2720 let { fp_pos = pos1; _ } = param1 in
2721 let { fp_pos = pos2; _ } = param2 in
2722 match (get_fp_accept_disposable param1, get_fp_accept_disposable param2) with
2723 | (true, false) ->
2724 invalid
2725 ~fail:(fun () ->
2726 Errors.accept_disposable_invariant pos1 pos2 subtype_env.on_error)
2728 | (false, true) ->
2729 invalid
2730 ~fail:(fun () ->
2731 Errors.accept_disposable_invariant pos2 pos1 subtype_env.on_error)
2733 | (_, _) -> valid env
2735 and simplify_param_ifc ~subtype_env sub super env =
2736 let { fp_pos = pos1; _ } = sub in
2737 let { fp_pos = pos2; _ } = super in
2738 (* TODO: also handle <<CanCall>> *)
2739 match (get_fp_ifc_external sub, get_fp_ifc_external super) with
2740 | (true, false) ->
2741 invalid
2742 ~fail:(fun () ->
2743 Errors.ifc_external_contravariant pos2 pos1 subtype_env.on_error)
2745 | _ -> valid env
2747 and ifc_policy_matches (ifc1 : ifc_fun_decl) (ifc2 : ifc_fun_decl) =
2748 match (ifc1, ifc2) with
2749 | (FDPolicied (Some s1), FDPolicied (Some s2)) when String.equal s1 s2 -> true
2750 | (FDPolicied None, FDPolicied None) -> true
2751 (* TODO(T79510128): IFC needs to check that the constraints inferred by the parent entail those by the subtype *)
2752 | (FDInferFlows, FDInferFlows) -> true
2753 | _ -> false
2755 (* Helper function for subtyping on function types: performs all checks that
2756 * don't involve actual types:
2757 * <<__ReturnDisposable>> attribute
2758 * <<__MutableReturn>> attribute
2759 * <<__Rx>> attribute
2760 * <<__Mutable>> attribute
2761 * variadic arity
2762 * <<__Policied>> attribute
2764 and simplify_subtype_funs_attributes
2765 ~subtype_env
2766 ?(extra_info : reactivity_extra_info option)
2767 (r_sub : Reason.t)
2768 (ft_sub : locl_fun_type)
2769 (r_super : Reason.t)
2770 (ft_super : locl_fun_type)
2771 env =
2772 let p_sub = Reason.to_pos r_sub in
2773 let p_super = Reason.to_pos r_super in
2774 let on_error_reactivity ?code:_ _ _ =
2775 Errors.fun_reactivity_mismatch
2776 p_super
2777 (TUtils.reactivity_to_string env ft_super.ft_reactive)
2778 p_sub
2779 (TUtils.reactivity_to_string env ft_sub.ft_reactive)
2780 subtype_env.on_error
2782 let ifc_policy_err_str = function
2783 | FDPolicied (Some s) -> s
2784 | FDPolicied None -> "the existential policy"
2785 | FDInferFlows -> "an inferred policy"
2787 simplify_subtype_reactivity
2788 ~subtype_env:{ subtype_env with on_error = on_error_reactivity }
2789 ?extra_info
2790 p_sub
2791 ft_sub.ft_reactive
2792 p_super
2793 ft_super.ft_reactive
2795 |> check_with
2796 (ifc_policy_matches ft_sub.ft_ifc_decl ft_super.ft_ifc_decl)
2797 (fun () ->
2798 Errors.ifc_policy_mismatch
2799 p_sub
2800 p_super
2801 (ifc_policy_err_str ft_sub.ft_ifc_decl)
2802 (ifc_policy_err_str ft_super.ft_ifc_decl)
2803 subtype_env.on_error)
2804 |> check_with
2805 (Bool.equal
2806 (get_ft_return_disposable ft_sub)
2807 (get_ft_return_disposable ft_super))
2808 (fun () ->
2809 Errors.return_disposable_mismatch
2810 (get_ft_return_disposable ft_super)
2811 p_super
2812 p_sub
2813 subtype_env.on_error)
2814 |> (* it is ok for subclass to return mutably owned value and treat it as immutable -
2815 the fact that value is mutably owned guarantees it has only single reference so
2816 as a result this single reference will be immutable. However if super type
2817 returns mutable value and subtype yields immutable value - this is not safe.
2818 NOTE: error is not reported if child is non-reactive since it does not have
2819 immutability-by-default behavior *)
2820 check_with
2821 ( Bool.equal
2822 (get_ft_returns_mutable ft_sub)
2823 (get_ft_returns_mutable ft_super)
2824 || (not (get_ft_returns_mutable ft_super))
2825 || not (any_reactive ft_sub.ft_reactive) )
2826 (fun () ->
2827 Errors.mutable_return_result_mismatch
2828 (get_ft_returns_mutable ft_super)
2829 p_super
2830 p_sub
2831 subtype_env.on_error)
2832 |> check_with
2833 ( (not (any_reactive ft_super.ft_reactive))
2834 || get_ft_returns_void_to_rx ft_super
2835 || not (get_ft_returns_void_to_rx ft_sub) )
2836 (fun () ->
2837 (* __ReturnsVoidToRx can be omitted on subtype, in this case using subtype
2838 via reference to supertype in rx context will be ok since result will be
2839 discarded. The opposite is not true:
2840 class A {
2841 <<__Rx, __Mutable>>
2842 public function f(): A { return new A(); }
2844 class B extends A {
2845 <<__Rx, __Mutable, __ReturnsVoidToRx>>
2846 public function f(): A { return $this; }
2849 <<__Rx, __MutableReturn>>
2850 function f(): A { return new B(); }
2851 $a = HH\Rx\mutable(f());
2852 $a1 = $a->f(); // immutable alias to mutable reference *)
2853 Errors.return_void_to_rx_mismatch
2854 ~pos1_has_attribute:true
2855 p_sub
2856 p_super
2857 subtype_env.on_error)
2859 (* check mutability only for reactive functions *)
2860 let check_params_mutability =
2861 any_reactive ft_super.ft_reactive && any_reactive ft_sub.ft_reactive
2863 fun (env, prop) ->
2864 ( if check_params_mutability (* check mutability of receivers *) then
2865 (env, prop)
2866 &&& check_mutability
2867 ~is_receiver:true
2868 ~subtype_env
2869 p_super
2870 (get_ft_param_mutable ft_super)
2871 p_sub
2872 (get_ft_param_mutable ft_sub)
2873 else
2874 (env, prop) )
2875 |> check_with
2876 (arity_min ft_sub <= arity_min ft_super)
2877 (fun () ->
2878 Errors.fun_too_many_args
2879 (arity_min ft_super)
2880 (arity_min ft_sub)
2881 p_sub
2882 p_super
2883 subtype_env.on_error)
2884 |> fun res ->
2885 match (ft_sub.ft_arity, ft_super.ft_arity) with
2886 | (Fvariadic { fp_name = None; _ }, Fvariadic { fp_name = Some _; _ }) ->
2887 (* The HHVM runtime ignores "..." entirely, but knows about
2888 * "...$args"; for contexts for which the runtime enforces method
2889 * compatibility (currently, inheritance from abstract/interface
2890 * methods), letting "..." override "...$args" would result in method
2891 * compatibility errors at runtime. *)
2892 with_error
2893 (fun () ->
2894 Errors.fun_variadicity_hh_vs_php56 p_sub p_super subtype_env.on_error)
2896 | (Fstandard, Fstandard) ->
2897 let sub_max = List.length ft_sub.ft_params in
2898 let super_max = List.length ft_super.ft_params in
2899 if sub_max < super_max then
2900 with_error
2901 (fun () ->
2902 Errors.fun_too_few_args
2903 super_max
2904 sub_max
2905 p_sub
2906 p_super
2907 subtype_env.on_error)
2909 else
2911 | (Fstandard, _) ->
2912 with_error
2913 (fun () ->
2914 Errors.fun_unexpected_nonvariadic p_sub p_super subtype_env.on_error)
2916 | (_, _) -> res
2918 and simplify_subtype_possibly_enforced
2919 ~(subtype_env : subtype_env) et_sub et_super =
2920 simplify_subtype ~subtype_env et_sub.et_type et_super.et_type
2922 (* This implements basic subtyping on non-generic function types:
2923 * (1) return type behaves covariantly
2924 * (2) parameter types behave contravariantly
2925 * (3) special casing for variadics, and various reactivity and mutability attributes
2927 and simplify_subtype_funs
2928 ~(subtype_env : subtype_env)
2929 ~(check_return : bool)
2930 ?(extra_info : reactivity_extra_info option)
2931 (r_sub : Reason.t)
2932 (ft_sub : locl_fun_type)
2933 (r_super : Reason.t)
2934 (ft_super : locl_fun_type)
2935 env : env * TL.subtype_prop =
2936 let variadic_subtype =
2937 match ft_sub.ft_arity with
2938 | Fvariadic { fp_type = var_sub; _ } -> Some var_sub
2939 | _ -> None
2941 let variadic_supertype =
2942 match ft_super.ft_arity with
2943 | Fvariadic { fp_type = var_super; _ } -> Some var_super
2944 | _ -> None
2946 let simplify_subtype_possibly_enforced =
2947 simplify_subtype_possibly_enforced ~subtype_env
2949 let simplify_subtype_params = simplify_subtype_params ~subtype_env in
2950 (* First apply checks on attributes and variadic arity *)
2951 let simplify_subtype_implicit_params =
2952 simplify_subtype_implicit_params ~subtype_env
2955 |> simplify_subtype_funs_attributes
2956 ~subtype_env
2957 ?extra_info
2958 r_sub
2959 ft_sub
2960 r_super
2961 ft_super
2962 &&& (* Now do contravariant subtyping on parameters *)
2963 begin
2964 match (variadic_subtype, variadic_supertype) with
2965 | (Some var_sub, Some var_super) ->
2966 simplify_subtype_possibly_enforced var_super var_sub
2967 | _ -> valid
2969 &&& begin
2970 let check_params_mutability =
2971 any_reactive ft_super.ft_reactive && any_reactive ft_sub.ft_reactive
2973 (* If both fun policies are IFC public, there's no need to check for inheritance issues *)
2974 (* There is the chance that the super function has an <<__External>> argument and the sub function does not,
2975 but <<__External>> on a public policied function literally just means the argument must be governed by the public policy,
2976 so should be an error in any case.
2978 let check_params_ifc =
2979 non_public_ifc ft_super.ft_ifc_decl
2980 || non_public_ifc ft_sub.ft_ifc_decl
2982 let is_method =
2983 Option.equal
2984 Bool.equal
2985 (Option.map extra_info (fun i -> Option.is_some i.method_info))
2986 (Some true)
2988 simplify_subtype_params
2989 ~is_method
2990 ~check_params_reactivity:(should_check_fun_params_reactivity ft_super)
2991 ~check_params_mutability
2992 ~check_params_ifc
2993 ft_super.ft_params
2994 ft_sub.ft_params
2995 variadic_subtype
2996 variadic_supertype
2998 &&& simplify_subtype_implicit_params
2999 ft_super.ft_implicit_params
3000 ft_sub.ft_implicit_params
3002 (* Finally do covariant subtryping on return type *)
3003 if check_return then
3004 simplify_subtype_possibly_enforced ft_sub.ft_ret ft_super.ft_ret
3005 else
3006 valid
3008 (* One of the main entry points to this module *)
3009 and sub_type_i
3010 ~subtype_env (env : env) (ty_sub : internal_type) (ty_super : internal_type)
3011 : env =
3012 Env.log_env_change "sub_type" env
3014 let old_env = env in
3015 let (env, success) =
3016 sub_type_inner ~subtype_env env ~this_ty:None ty_sub ty_super
3018 if success then
3020 else
3021 old_env
3023 and sub_type
3025 ?(allow_subtype_of_dynamic = false)
3026 (ty_sub : locl_ty)
3027 (ty_super : locl_ty)
3028 on_error =
3029 sub_type_i
3030 ~subtype_env:
3031 (make_subtype_env
3032 ~allow_subtype_of_dynamic
3033 ~treat_dynamic_as_bottom:false
3034 on_error)
3036 (LoclType ty_sub)
3037 (LoclType ty_super)
3039 (* Add a new upper bound ty on var. Apply transitivity of sutyping,
3040 * so if we already have tyl <: var, then check that for each ty_sub
3041 * in tyl we have ty_sub <: ty.
3043 and add_tyvar_upper_bound_and_close
3044 ~treat_dynamic_as_bottom (env, prop) var ty on_error =
3045 let upper_bounds_before = Env.get_tyvar_upper_bounds env var in
3046 let env =
3047 Env.add_tyvar_upper_bound_and_update_variances
3048 ~intersect:(try_intersect_i env)
3053 let upper_bounds_after = Env.get_tyvar_upper_bounds env var in
3054 let added_upper_bounds = ITySet.diff upper_bounds_after upper_bounds_before in
3055 let lower_bounds = Env.get_tyvar_lower_bounds env var in
3056 let (env, prop) =
3057 ITySet.fold
3058 (fun upper_bound (env, prop) ->
3059 let env =
3060 Typing_subtype_tconst.make_all_type_consts_equal
3063 upper_bound
3064 ~on_error
3065 ~as_tyvar_with_cnstr:true
3067 ITySet.fold
3068 (fun lower_bound (env, prop1) ->
3069 let (env, prop2) =
3070 simplify_subtype_i
3071 ~subtype_env:
3072 (make_subtype_env ~treat_dynamic_as_bottom on_error)
3073 lower_bound
3074 upper_bound
3077 (env, TL.conj prop1 prop2))
3078 lower_bounds
3079 (env, prop))
3080 added_upper_bounds
3081 (env, prop)
3083 (env, prop)
3085 (* Add a new lower bound ty on var. Apply transitivity of subtyping
3086 * (so if var <: ty1,...,tyn then assert ty <: tyi for each tyi), using
3087 * simplify_subtype to produce a subtype proposition.
3089 and add_tyvar_lower_bound_and_close
3090 ~treat_dynamic_as_bottom (env, prop) var ty on_error =
3091 let lower_bounds_before = Env.get_tyvar_lower_bounds env var in
3092 let env =
3093 Env.add_tyvar_lower_bound_and_update_variances
3094 ~union:(try_union_i env)
3099 let lower_bounds_after = Env.get_tyvar_lower_bounds env var in
3100 let added_lower_bounds = ITySet.diff lower_bounds_after lower_bounds_before in
3101 let upper_bounds = Env.get_tyvar_upper_bounds env var in
3102 let (env, prop) =
3103 ITySet.fold
3104 (fun lower_bound (env, prop) ->
3105 let env =
3106 Typing_subtype_tconst.make_all_type_consts_equal
3109 lower_bound
3110 ~on_error
3111 ~as_tyvar_with_cnstr:false
3113 ITySet.fold
3114 (fun upper_bound (env, prop1) ->
3115 let (env, prop2) =
3116 simplify_subtype_i
3117 ~subtype_env:
3118 (make_subtype_env ~treat_dynamic_as_bottom on_error)
3119 lower_bound
3120 upper_bound
3123 (env, TL.conj prop1 prop2))
3124 upper_bounds
3125 (env, prop))
3126 added_lower_bounds
3127 (env, prop)
3129 (env, prop)
3131 and get_tyvar_opt t =
3132 match t with
3133 | LoclType lt ->
3134 begin
3135 match get_node lt with
3136 | Tvar var -> Some var
3137 | _ -> None
3139 | _ -> None
3141 and props_to_env env remain props on_error =
3142 match props with
3143 | [] -> (env, List.rev remain)
3144 | prop :: props ->
3145 (match prop with
3146 | TL.Conj props' -> props_to_env env remain (props' @ props) on_error
3147 | TL.Disj (f, disj_props) ->
3148 (* For now, just find the first prop in the disjunction that works *)
3149 let rec try_disj disj_props =
3150 match disj_props with
3151 | [] ->
3152 (* For now let it fail later when calling
3153 process_simplify_subtype_result on the remaining constraints. *)
3154 props_to_env env (TL.invalid ~fail:f :: remain) props on_error
3155 | prop :: disj_props' ->
3156 let (env', other) = props_to_env env remain [prop] on_error in
3157 if TL.is_unsat (TL.conj_list other) then
3158 try_disj disj_props'
3159 else
3160 props_to_env env' (remain @ other) props on_error
3162 try_disj disj_props
3163 | TL.IsSubtype (ty_sub, ty_super) ->
3164 begin
3165 match (get_tyvar_opt ty_sub, get_tyvar_opt ty_super) with
3166 | (Some var_sub, Some var_super) ->
3167 let (env, prop1) =
3168 add_tyvar_upper_bound_and_close
3169 ~treat_dynamic_as_bottom:false
3170 (valid env)
3171 var_sub
3172 ty_super
3173 on_error
3175 let (env, prop2) =
3176 add_tyvar_lower_bound_and_close
3177 ~treat_dynamic_as_bottom:false
3178 (valid env)
3179 var_super
3180 ty_sub
3181 on_error
3183 props_to_env env remain (prop1 :: prop2 :: props) on_error
3184 | (Some var, _) ->
3185 let (env, prop) =
3186 add_tyvar_upper_bound_and_close
3187 ~treat_dynamic_as_bottom:false
3188 (valid env)
3190 ty_super
3191 on_error
3193 props_to_env env remain (prop :: props) on_error
3194 | (_, Some var) ->
3195 let (env, prop) =
3196 add_tyvar_lower_bound_and_close
3197 ~treat_dynamic_as_bottom:false
3198 (valid env)
3200 ty_sub
3201 on_error
3203 props_to_env env remain (prop :: props) on_error
3204 | _ -> props_to_env env (prop :: remain) props on_error
3206 | TL.Coerce (ty_sub, ty_super) ->
3207 begin
3208 match (get_node ty_sub, get_node ty_super) with
3209 | (Tvar var_sub, Tvar var_super) ->
3210 let (env, prop1) =
3211 add_tyvar_upper_bound_and_close
3212 ~treat_dynamic_as_bottom:true
3213 (valid env)
3214 var_sub
3215 (LoclType ty_super)
3216 on_error
3218 let (env, prop2) =
3219 add_tyvar_lower_bound_and_close
3220 ~treat_dynamic_as_bottom:true
3221 (valid env)
3222 var_super
3223 (LoclType ty_sub)
3224 on_error
3226 props_to_env env remain (prop1 :: prop2 :: props) on_error
3227 | (Tvar var, _) ->
3228 let (env, prop) =
3229 add_tyvar_upper_bound_and_close
3230 ~treat_dynamic_as_bottom:true
3231 (valid env)
3233 (LoclType ty_super)
3234 on_error
3236 props_to_env env remain (prop :: props) on_error
3237 | (_, Tvar var) ->
3238 let (env, prop) =
3239 add_tyvar_lower_bound_and_close
3240 ~treat_dynamic_as_bottom:true
3241 (valid env)
3243 (LoclType ty_sub)
3244 on_error
3246 props_to_env env remain (prop :: props) on_error
3247 | _ -> failwith "Coercion not expected"
3248 end)
3250 (* Move any top-level conjuncts of the form Tvar v <: t or t <: Tvar v to
3251 * the type variable environment. To do: use intersection and union to
3252 * simplify bounds.
3254 and prop_to_env env prop on_error =
3255 let (env, props') = props_to_env env [] [prop] on_error in
3256 (env, TL.conj_list props')
3258 and sub_type_inner
3259 (env : env)
3260 ~(subtype_env : subtype_env)
3261 ~(this_ty : locl_ty option)
3262 (ty_sub : internal_type)
3263 (ty_super : internal_type) : env * bool =
3264 log_subtype_i
3265 ~level:1
3266 ~this_ty
3267 ~function_name:"sub_type_inner"
3269 ty_sub
3270 ty_super;
3271 let (env, prop) =
3272 simplify_subtype_i ~subtype_env ~this_ty ty_sub ty_super env
3274 let (env, prop) = prop_to_env env prop subtype_env.on_error in
3275 let env = Env.add_subtype_prop env prop in
3276 let succeeded = process_simplify_subtype_result prop in
3277 (env, succeeded)
3279 and is_sub_type_alt_i
3280 ~ignore_generic_params
3281 ~no_top_bottom
3282 ~treat_dynamic_as_bottom
3283 ~allow_subtype_of_dynamic
3286 ty2 =
3287 let (this_ty, pos) =
3288 match ty1 with
3289 | LoclType ty1 -> (Some ty1, get_pos ty1)
3290 | ConstraintType _ -> (None, Pos.none)
3292 let (_env, prop) =
3293 simplify_subtype_i
3294 ~subtype_env:
3296 seen_generic_params =
3297 ( if ignore_generic_params then
3298 None
3299 else
3300 empty_seen );
3301 no_top_bottom;
3302 treat_dynamic_as_bottom;
3303 allow_subtype_of_dynamic;
3304 on_error = Errors.unify_error_at pos;
3306 ~this_ty
3307 (* It is weird that this can cause errors, but I am wary to discard them.
3308 * Using the generic unify_error to maintain current behavior. *)
3313 if TL.is_valid prop then
3314 Some true
3315 else if TL.is_unsat prop then
3316 Some false
3317 else
3318 None
3320 and is_sub_type_alt ~ignore_generic_params ~no_top_bottom env ty1 ty2 =
3321 is_sub_type_alt_i
3322 ~ignore_generic_params
3323 ~no_top_bottom
3325 (LoclType ty1)
3326 (LoclType ty2)
3328 and is_sub_type env ty1 ty2 =
3329 let ( = ) = Option.equal Bool.equal in
3330 is_sub_type_alt
3331 ~ignore_generic_params:false
3332 ~no_top_bottom:false
3333 ~treat_dynamic_as_bottom:false
3334 ~allow_subtype_of_dynamic:false
3338 = Some true
3340 and is_sub_type_for_coercion env ty1 ty2 =
3341 let ( = ) = Option.equal Bool.equal in
3342 is_sub_type_alt
3343 ~ignore_generic_params:false
3344 ~no_top_bottom:false
3345 ~treat_dynamic_as_bottom:true
3346 ~allow_subtype_of_dynamic:true
3350 = Some true
3352 and is_sub_type_for_union env ?allow_subtype_of_dynamic:(asod = false) ty1 ty2 =
3353 let ( = ) = Option.equal Bool.equal in
3354 is_sub_type_alt
3355 ~ignore_generic_params:false
3356 ~no_top_bottom:true
3357 ~treat_dynamic_as_bottom:false
3358 ~allow_subtype_of_dynamic:asod
3362 = Some true
3364 and is_sub_type_for_union_i env ?allow_subtype_of_dynamic:(asod = false) ty1 ty2
3366 let ( = ) = Option.equal Bool.equal in
3367 is_sub_type_alt_i
3368 ~ignore_generic_params:false
3369 ~no_top_bottom:true
3370 ~treat_dynamic_as_bottom:false
3371 ~allow_subtype_of_dynamic:asod
3375 = Some true
3377 and can_sub_type env ty1 ty2 =
3378 let ( <> ) a b = not (Option.equal Bool.equal a b) in
3379 is_sub_type_alt
3380 ~ignore_generic_params:false
3381 ~no_top_bottom:true
3382 ~treat_dynamic_as_bottom:false
3383 ~allow_subtype_of_dynamic:false
3387 <> Some false
3389 and is_sub_type_ignore_generic_params env ty1 ty2 =
3390 let ( = ) = Option.equal Bool.equal in
3391 is_sub_type_alt
3392 ~ignore_generic_params:true
3393 ~no_top_bottom:true
3394 ~treat_dynamic_as_bottom:false
3395 ~allow_subtype_of_dynamic:false
3399 = Some true
3401 and is_sub_type_ignore_generic_params_i env ty1 ty2 =
3402 let ( = ) = Option.equal Bool.equal in
3403 is_sub_type_alt_i
3404 ~ignore_generic_params:true
3405 ~no_top_bottom:true
3406 ~treat_dynamic_as_bottom:false
3407 ~allow_subtype_of_dynamic:false
3411 = Some true
3413 (* Attempt to compute the intersection of a type with an existing list intersection.
3414 * If try_intersect env t [t1;...;tn] = [u1; ...; um]
3415 * then u1&...&um must be the greatest lower bound of t and t1&...&tn wrt subtyping.
3416 * For example:
3417 * try_intersect nonnull [?C] = [C]
3418 * try_intersect t1 [t2] = [t1] if t1 <: t2
3419 * Note: it's acceptable to return [t;t1;...;tn] but the intention is that
3420 * we simplify (as above) wherever practical.
3421 * It can be assumed that the original list contains no redundancy.
3423 and try_intersect_i env ty tyl =
3424 match tyl with
3425 | [] -> [ty]
3426 | ty' :: tyl' ->
3427 if is_sub_type_ignore_generic_params_i env ty ty' then
3428 try_intersect_i env ty tyl'
3429 else if is_sub_type_ignore_generic_params_i env ty' ty then
3431 else
3432 let nonnull_ty = LoclType (MakeType.nonnull (reason ty)) in
3433 let (env, ty) = Env.expand_internal_type env ty in
3434 let (env, ty') = Env.expand_internal_type env ty' in
3435 let default env = ty' :: try_intersect_i env ty tyl' in
3436 (match (ty, ty') with
3437 | (LoclType lty, _)
3438 when is_sub_type_ignore_generic_params_i env ty' nonnull_ty ->
3439 begin
3440 match get_node lty with
3441 | Toption t -> try_intersect_i env (LoclType t) (ty' :: tyl')
3442 | _ -> default env
3444 | (_, LoclType lty)
3445 when is_sub_type_ignore_generic_params_i env ty nonnull_ty ->
3446 begin
3447 match get_node lty with
3448 | Toption t -> try_intersect_i env (LoclType t) (ty :: tyl')
3449 | _ -> default env
3451 | (_, _) -> default env)
3453 and try_intersect env ty tyl =
3454 List.map
3455 (try_intersect_i
3457 (LoclType ty)
3458 (List.map tyl ~f:(fun ty -> LoclType ty)))
3459 ~f:(function
3460 | LoclType ty -> ty
3461 | _ ->
3462 failwith
3463 "The intersection of two locl type should always be a locl type.")
3465 (* Attempt to compute the union of a type with an existing list union.
3466 * If try_union env t [t1;...;tn] = [u1;...;um]
3467 * then u1|...|um must be the least upper bound of t and t1|...|tn wrt subtyping.
3468 * For example:
3469 * try_union int [float] = [num]
3470 * try_union t1 [t2] = [t1] if t2 <: t1
3472 * Notes:
3473 * 1. It's acceptable to return [t;t1;...;tn] but the intention is that
3474 * we simplify (as above) wherever practical.
3475 * 2. Do not use Tunion for a syntactic union - the caller can do that.
3476 * 3. It can be assumed that the original list contains no redundancy.
3477 * TODO: there are many more unions to implement yet.
3479 and try_union_i env ty tyl =
3480 match tyl with
3481 | [] -> [ty]
3482 | ty' :: tyl' ->
3483 if is_sub_type_for_union_i env ty ty' then
3485 else if is_sub_type_for_union_i env ty' ty then
3486 try_union_i env ty tyl'
3487 else
3488 let (env, ty) = Env.expand_internal_type env ty in
3489 let (env, ty') = Env.expand_internal_type env ty' in
3490 (match (ty, ty') with
3491 | (LoclType t1, LoclType t2)
3492 when (is_prim Nast.Tfloat t1 && is_prim Nast.Tint t2)
3493 || (is_prim Nast.Tint t1 && is_prim Nast.Tfloat t2) ->
3494 let num = LoclType (MakeType.num (reason ty)) in
3495 try_union_i env num tyl'
3496 | (_, _) -> ty' :: try_union_i env ty tyl')
3498 and try_union env ty tyl =
3499 List.map
3500 (try_union_i env (LoclType ty) (List.map tyl ~f:(fun ty -> LoclType ty)))
3501 ~f:(function
3502 | LoclType ty -> ty
3503 | _ -> failwith "The union of two locl type should always be a locl type.")
3505 let subtype_reactivity
3506 ?extra_info ?is_call_site env p_sub r_sub p_super r_super on_error =
3507 let subtype_env = make_subtype_env ~treat_dynamic_as_bottom:false on_error in
3508 let (env, prop) =
3509 simplify_subtype_reactivity
3510 ~subtype_env
3511 ?extra_info
3512 ?is_call_site
3513 p_sub
3514 r_sub
3515 p_super
3516 r_super
3519 let (env, prop) = prop_to_env env prop subtype_env.on_error in
3520 ignore (process_simplify_subtype_result prop);
3523 let decompose_subtype_add_bound
3524 (env : env) (ty_sub : locl_ty) (ty_super : locl_ty) : env =
3525 let (env, ty_super) = Env.expand_type env ty_super in
3526 let (env, ty_sub) = Env.expand_type env ty_sub in
3527 match (get_node ty_sub, get_node ty_super) with
3528 | (_, Tany _) -> env
3529 (* name_sub <: ty_super so add an upper bound on name_sub *)
3530 | (Tgeneric (name_sub, targs), _) when not (phys_equal ty_sub ty_super) ->
3531 (* TODO(T69551141) handle type arguments. Passing targs to get_lower_bounds,
3532 but the add_upper_bound call must be adapted *)
3533 log_subtype
3534 ~level:2
3535 ~this_ty:None
3536 ~function_name:"decompose_subtype_add_bound"
3538 ty_sub
3539 ty_super;
3540 let tys = Env.get_upper_bounds env name_sub targs in
3541 (* Don't add the same type twice! *)
3542 if Typing_set.mem ty_super tys then
3544 else
3545 Env.add_upper_bound ~intersect:(try_intersect env) env name_sub ty_super
3546 (* ty_sub <: name_super so add a lower bound on name_super *)
3547 | (_, Tgeneric (name_super, targs)) when not (phys_equal ty_sub ty_super) ->
3548 (* TODO(T69551141) handle type arguments. Passing targs to get_lower_bounds,
3549 but the add_lower_bound call must be adapted *)
3550 log_subtype
3551 ~level:2
3552 ~this_ty:None
3553 ~function_name:"decompose_subtype_add_bound"
3555 ty_sub
3556 ty_super;
3557 let tys = Env.get_lower_bounds env name_super targs in
3558 (* Don't add the same type twice! *)
3559 if Typing_set.mem ty_sub tys then
3561 else
3562 Env.add_lower_bound ~union:(try_union env) env name_super ty_sub
3563 | (_, _) -> env
3565 (* Given two types that we know are in a subtype relationship
3566 * ty_sub <: ty_super
3567 * add to env.tpenv any bounds on generic type parameters that must
3568 * hold for ty_sub <: ty_super to be valid.
3570 * For example, suppose we know Cov<T> <: Cov<D> for a covariant class Cov.
3571 * Then it must be the case that T <: D so we add an upper bound D to the
3572 * bounds for T.
3574 * Although some of this code is similar to that for sub_type_inner, its
3575 * purpose is different. sub_type_inner takes two types t and u and makes
3576 * updates to the substitution of type variables (through unification) to
3577 * make t <: u true.
3579 * decompose_subtype takes two types t and u for which t <: u is *assumed* to
3580 * hold, and makes updates to bounds on generic parameters that *necessarily*
3581 * hold in order for t <: u.
3583 let rec decompose_subtype
3585 (env : env)
3586 (ty_sub : locl_ty)
3587 (ty_super : locl_ty)
3588 (on_error : Errors.typing_error_callback) : env =
3589 log_subtype
3590 ~level:2
3591 ~this_ty:None
3592 ~function_name:"decompose_subtype"
3594 ty_sub
3595 ty_super;
3596 let (env, prop) =
3597 simplify_subtype
3598 ~subtype_env:(make_subtype_env ~seen_generic_params:None on_error)
3599 ~this_ty:None
3600 ty_sub
3601 ty_super
3604 decompose_subtype_add_prop p env prop
3606 and decompose_subtype_add_prop p env prop =
3607 match prop with
3608 | TL.Conj props ->
3609 List.fold_left ~f:(decompose_subtype_add_prop p) ~init:env props
3610 | TL.Disj (_, []) -> Env.mark_inconsistent env
3611 | TL.Disj (_, [prop']) -> decompose_subtype_add_prop p env prop'
3612 | TL.Disj _ ->
3613 Typing_log.log_prop 2 env.function_pos "decompose_subtype_add_prop" env prop;
3615 | TL.Coerce _ -> failwith "Coercions should have been resolved beforehand"
3616 | TL.IsSubtype (LoclType ty1, LoclType ty2) ->
3617 decompose_subtype_add_bound env ty1 ty2
3618 | TL.IsSubtype _ ->
3619 failwith
3620 "Subtyping locl types should yield propositions involving locl types only."
3622 (* Decompose a general constraint *)
3623 and decompose_constraint
3625 (env : env)
3626 (ck : Ast_defs.constraint_kind)
3627 (ty_sub : locl_ty)
3628 (ty_super : locl_ty) : env =
3629 (* constraints are caught based on reason, not error callback. Using unify_error *)
3630 match ck with
3631 | Ast_defs.Constraint_as ->
3632 decompose_subtype p env ty_sub ty_super (Errors.unify_error_at p)
3633 | Ast_defs.Constraint_super ->
3634 decompose_subtype p env ty_super ty_sub (Errors.unify_error_at p)
3635 | Ast_defs.Constraint_eq ->
3636 let env =
3637 decompose_subtype p env ty_sub ty_super (Errors.unify_error_at p)
3639 decompose_subtype p env ty_super ty_sub (Errors.unify_error_at p)
3641 (* Given a constraint ty1 ck ty2 where ck is AS, SUPER or =,
3642 * add bounds to type parameters in the environment that necessarily
3643 * must hold in order for ty1 ck ty2.
3645 * First, we invoke decompose_constraint to add initial bounds to
3646 * the environment. Then we iterate, decomposing constraints that
3647 * arise through transitivity across bounds.
3649 * For example, suppose that env already contains
3650 * C<T1> <: T2
3651 * for some covariant class C. Now suppose we add the
3652 * constraint "T2 as C<T3>" i.e. we end up with
3653 * C<T1> <: T2 <: C<T3>
3654 * Then by transitivity we know that T1 <: T3 so we add this to the
3655 * environment too.
3657 * We repeat this process until no further bounds are added to the
3658 * environment, or some limit is reached. (It's possible to construct
3659 * types that expand forever under inheritance.)
3661 let constraint_iteration_limit = 20
3663 let add_constraint
3665 (env : env)
3666 (ck : Ast_defs.constraint_kind)
3667 (ty_sub : locl_ty)
3668 (ty_super : locl_ty) : env =
3669 log_subtype
3670 ~level:1
3671 ~this_ty:None
3672 ~function_name:"add_constraint"
3674 ty_sub
3675 ty_super;
3676 let oldsize = Env.get_tpenv_size env in
3677 let env = decompose_constraint p env ck ty_sub ty_super in
3678 let ( = ) = Int.equal in
3679 if Env.get_tpenv_size env = oldsize then
3681 else
3682 let rec iter n env =
3683 if n > constraint_iteration_limit then
3685 else
3686 let oldsize = Env.get_tpenv_size env in
3687 let env =
3688 List.fold_left
3689 (Env.get_generic_parameters env)
3690 ~init:env
3691 ~f:(fun env x ->
3692 List.fold_left
3693 (* TODO(T70068435) always using [] as args for now *)
3694 (Typing_set.elements (Env.get_lower_bounds env x []))
3695 ~init:env
3696 ~f:(fun env ty_sub' ->
3697 List.fold_left
3698 (* TODO(T70068435) always using [] as args for now *)
3699 (Typing_set.elements (Env.get_upper_bounds env x []))
3700 ~init:env
3701 ~f:(fun env ty_super' ->
3702 decompose_subtype
3705 ty_sub'
3706 ty_super'
3707 (Errors.unify_error_at p))))
3709 if Int.equal (Env.get_tpenv_size env) oldsize then
3711 else
3712 iter (n + 1) env
3714 iter 0 env
3716 let add_constraints p env constraints =
3717 let add_constraint env (ty1, ck, ty2) = add_constraint p env ck ty1 ty2 in
3718 List.fold_left constraints ~f:add_constraint ~init:env
3720 let sub_type_with_dynamic_as_bottom
3721 (env : env)
3722 (ty_sub : locl_ty)
3723 (ty_super : locl_ty)
3724 (on_error : Errors.typing_error_callback) : env =
3725 let env_change_log = Env.log_env_change "coercion" env in
3726 log_subtype
3727 ~level:1
3728 ~this_ty:None
3729 ~function_name:"coercion"
3731 ty_sub
3732 ty_super;
3733 let old_env = env in
3734 let (env, prop) =
3735 simplify_subtype
3736 ~subtype_env:(make_subtype_env ~treat_dynamic_as_bottom:true on_error)
3737 ~this_ty:None
3738 ty_sub
3739 ty_super
3742 let (env, prop) = prop_to_env env prop on_error in
3743 let env = Env.add_subtype_prop env prop in
3744 let succeeded = process_simplify_subtype_result prop in
3745 let env =
3746 if succeeded then
3748 else
3749 old_env
3751 env_change_log env
3753 let simplify_subtype_i env ty_sub ty_super ~on_error =
3754 simplify_subtype_i
3755 ~subtype_env:(make_subtype_env ~no_top_bottom:true on_error)
3756 ty_sub
3757 ty_super
3760 (*****************************************************************************)
3761 (* Exporting *)
3762 (*****************************************************************************)
3764 let sub_type_i env ty1 ty2 on_error =
3765 sub_type_i
3766 ~subtype_env:(make_subtype_env ~treat_dynamic_as_bottom:false on_error)
3771 let subtype_funs
3772 ~(check_return : bool)
3773 ~(extra_info : reactivity_extra_info)
3774 ~on_error
3775 (r_sub : Reason.t)
3776 (ft_sub : locl_fun_type)
3777 (r_super : Reason.t)
3778 (ft_super : locl_fun_type)
3779 env : env =
3780 let old_env = env in
3781 let (env, prop) =
3782 simplify_subtype_funs
3783 ~subtype_env:(make_subtype_env on_error)
3784 ~check_return
3785 ~extra_info
3786 r_sub
3787 ft_sub
3788 r_super
3789 ft_super
3792 let (env, prop) = prop_to_env env prop on_error in
3793 let env = Env.add_subtype_prop env prop in
3794 let succeeded = process_simplify_subtype_result prop in
3795 if succeeded then
3797 else
3798 old_env
3800 let sub_type_or_fail env ty1 ty2 fail =
3801 sub_type env ty1 ty2 (fun ?code:_ _ _ -> fail ())
3803 let set_fun_refs () =
3804 Typing_utils.sub_type_ref := sub_type;
3805 Typing_utils.sub_type_i_ref := sub_type_i;
3806 Typing_utils.sub_type_with_dynamic_as_bottom_ref :=
3807 sub_type_with_dynamic_as_bottom;
3808 Typing_utils.add_constraint_ref := add_constraint;
3809 Typing_utils.is_sub_type_ref := is_sub_type;
3810 Typing_utils.is_sub_type_for_union_ref := is_sub_type_for_union;
3811 Typing_utils.is_sub_type_for_union_i_ref := is_sub_type_for_union_i;
3812 Typing_utils.is_sub_type_ignore_generic_params_ref :=
3813 is_sub_type_ignore_generic_params
3815 let () = set_fun_refs ()