Remove polymorphic variant Typing_defs.dependent_type
[hiphop-php.git] / hphp / hack / src / typing / typing_subtype.ml
blob9f6ba6f6e9fdf18f67f3e352e1e3c584c225ddcc
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 Core_kernel
11 open Common
12 open Utils
13 open Typing_defs
15 module Reason = Typing_reason
16 module Unify = Typing_unify
17 module Env = Typing_env
18 module Inter = Typing_intersection
19 module Subst = Decl_subst
20 module TUtils = Typing_utils
21 module SN = Naming_special_names
22 module Phase = Typing_phase
23 module TL = Typing_logic
24 module Cls = Decl_provider.Class
25 module TySet = Typing_set
26 module MakeType = Typing_make_type
27 module Partial = Partial_provider
28 module ShapeMap = Nast.ShapeMap
29 module ShapeSet = Ast_defs.ShapeSet
30 module Nast = Aast
32 type reactivity_extra_info = {
33 method_info: ((* method_name *) string * (* is_static *) bool) option;
34 class_ty: phase_ty option;
35 parent_class_ty: phase_ty option
38 let empty_extra_info = {
39 method_info = None;
40 class_ty = None;
41 parent_class_ty = None
44 module ConditionTypes = struct
45 let try_get_class_for_condition_type (env: Env.env) (ty: decl ty) =
46 match TUtils.try_unwrap_class_type ty with
47 | None -> None
48 | Some (_, ((_, x) as sid), _) ->
49 begin match Env.get_class env x with
50 | None -> None
51 | Some cls -> Some (sid, cls)
52 end
54 let try_get_method_from_condition_type
55 (env: Env.env)
56 (ty: decl ty)
57 (is_static: bool)
58 (method_name: string) =
59 match try_get_class_for_condition_type env ty with
60 | Some (_, cls) ->
61 let get = if is_static then Cls.get_smethod else Cls.get_method in
62 get cls method_name
63 | None -> None
66 let localize_condition_type (env: Env.env) (ty: decl ty): locl ty =
67 (* if condition type is generic - we cannot specify type argument in attribute.
68 For cases when we check if containing type is a subtype of condition type
69 if condition type is generic instantiate it with TAny's *)
70 let do_localize ty =
71 let ty =
72 match try_get_class_for_condition_type env ty with
73 | None -> ty
74 | Some (_, cls) when Cls.tparams cls = [] -> ty
75 | Some (((p, _) as sid), cls) ->
76 let params =
77 List.map (Cls.tparams cls)
78 ~f:(fun { tp_name = (p,x); _ } -> Reason.Rwitness p, Tgeneric x) in
79 let subst =
80 Decl_instantiate.make_subst (Cls.tparams cls) [] in
81 let ty = Reason.Rwitness p, (Tapply (sid, params)) in
82 Decl_instantiate.instantiate subst ty in
83 let ety_env = Phase.env_with_self env in
84 let _, t = Phase.localize ~ety_env env ty in
87 match ty with
88 | r, Toption ty -> r, Toption (do_localize ty)
89 | ty -> do_localize ty
90 end
92 (* Given a pair of types `ty_sub` and `ty_super` attempt to apply simplifications
93 * and add to the accumulated constraints in `constraints` any necessary and
94 * sufficient [(t1,ck1,u1);...;(tn,ckn,un)] such that
95 * ty_sub <: ty_super iff t1 ck1 u1, ..., tn ckn un
96 * where ck is `as` or `=`. Essentially we are making solution-preserving
97 * simplifications to the subtype assertion, for now, also generating equalities
98 * as well as subtype assertions, for backwards compatibility with use of
99 * unification.
101 * If `constraints = []` is returned then the subtype assertion is valid.
103 * If the subtype assertion is unsatisfiable then return `failed = Some f`
104 * where `f` is a `unit-> unit` function that records an error message.
105 * (Sometimes we don't want to call this function e.g. when just checking if
106 * a subtype holds)
108 * Elide singleton unions, treat invariant generics as both-ways
109 * subtypes, and actually chase hierarchy for extends and implements.
111 * Annoyingly, we need to pass env back too, because Typing_phase.localize
112 * expands type constants. (TODO: work out a better way of handling this)
114 * Special cases:
115 * If assertion is valid (e.g. string <: arraykey) then
116 * result can be the empty list (i.e. nothing is added to the result)
117 * If assertion is unsatisfiable (e.g. arraykey <: string) then
118 * we record this in the failed field of the result.
120 let with_error (f : unit -> unit) ((env, p) : (Env.env * TL.subtype_prop))
121 : Env.env * TL.subtype_prop =
122 env, TL.conj p (TL.invalid ~fail:f)
124 (* If `b` is false then fail with error function `f` *)
125 let check_with b f r = if not b then with_error f r else r
127 let valid env : Env.env * TL.subtype_prop = env, TL.valid
129 let (&&&) (env, p1) (f : Env.env -> Env.env * TL.subtype_prop) =
130 if TL.is_unsat p1
131 then env, p1
132 else
133 let env, p2 = f env in
134 env, TL.conj p1 p2
136 let if_unsat (f : unit -> Env.env * TL.subtype_prop) (env, p) =
137 if TL.is_unsat p
138 then f ()
139 else env, p
141 let ignore_hh_fixmes f =
142 let is_hh_fixme = !Errors.is_hh_fixme in
143 Errors.is_hh_fixme := (fun _ _ -> false);
144 let result = f () in
145 Errors.is_hh_fixme := is_hh_fixme;
146 result
148 (** Check that a mutability type is a subtype of another mutability type *)
149 let check_mutability
150 ~(is_receiver: bool)
151 (p_sub : Pos.t)
152 (mut_sub: param_mutability option)
153 (p_super : Pos.t)
154 (mut_super: param_mutability option)
155 env =
156 let str m =
157 match m with
158 | None -> "immutable"
159 | Some Param_owned_mutable -> "owned mutable"
160 | Some Param_borrowed_mutable -> "mutable"
161 | Some Param_maybe_mutable -> "maybe-mutable" in
162 (* maybe-mutable <------immutable
164 <--mutable <-- owned mutable *)
165 match mut_sub, mut_super with
166 (* immutable is not compatible with mutable *)
167 | None, Some (Param_borrowed_mutable | Param_owned_mutable)
168 (* mutable is not compatible with immutable *)
169 | Some (Param_borrowed_mutable | Param_owned_mutable), None
170 (* borrowed mutable is not compatible with owned mutable *)
171 | Some Param_borrowed_mutable, Some Param_owned_mutable
172 (* maybe-mutable is not compatible with immutable/mutable *)
173 | Some Param_maybe_mutable, (None | Some (Param_borrowed_mutable | Param_owned_mutable))
175 env, TL.invalid ~fail:(fun () -> Errors.mutability_mismatch
176 ~is_receiver p_sub (str mut_sub) p_super (str mut_super))
177 | _ ->
178 valid env
180 let empty_seen = Some SSet.empty
182 let log_subtype ~level ~this_ty ~function_name env ty_sub ty_super =
183 Typing_log.(log_with_level env "sub" level begin fun () ->
184 let types =
185 [Log_type ("ty_sub", ty_sub);
186 Log_type ("ty_super", ty_super)] in
187 let types = Option.value_map this_ty ~default:types
188 ~f:(fun ty -> Log_type ("this_ty", ty) :: types) in
189 log_types (Reason.to_pos (fst ty_sub)) env
190 [Log_head (function_name, types)]
191 end)
193 let is_final_and_not_contravariant env id =
194 let class_def = Env.get_class env id in
195 match class_def with
196 | Some class_ty -> TUtils.class_is_final_and_not_contravariant class_ty
197 | None -> false
199 (** Make all types appearing in the given type a Tany, e.g.
200 - for A<B> return A<_>
201 - for function(A): B return function (_): _
203 let anyfy env r ty =
204 let anyfyer = object
205 inherit Type_mapper.deep_type_mapper as super
206 method! on_type env _ty = env, (r, Tany)
207 method go ty = let _, ty = super#on_type env ty in ty
208 end in
209 anyfyer#go ty
211 let find_type_with_exact_negation env tyl =
212 let rec find env tyl acc_tyl =
213 match tyl with
214 | [] -> env, None, acc_tyl
215 | ty :: tyl' ->
216 let env, non_ty = TUtils.non env (fst ty) ty TUtils.ApproxDown in
217 let nothing = MakeType.nothing Reason.none in
218 if ty_equal non_ty nothing then find env tyl' (ty :: acc_tyl) else
219 env, Some non_ty, tyl' @ acc_tyl in
220 find env tyl []
222 (* Process the constraint proposition *)
223 let rec process_simplify_subtype_result prop =
224 match prop with
225 | TL.IsSubtype (_ty1, _ty2) ->
226 (* All subtypes should have been resolved *)
227 assert false
228 | TL.Conj props ->
229 (* Evaluates list from left-to-right so preserves order of conjuncts *)
230 List.iter ~f:process_simplify_subtype_result props
231 | TL.Disj (f, props) ->
232 let rec try_disj props =
233 match props with
234 | [] ->
235 f ()
236 | prop :: props ->
237 Errors.try_
238 (fun () ->
239 ignore_hh_fixmes (fun () ->process_simplify_subtype_result prop))
240 (fun _ -> try_disj props)
242 try_disj props
244 (* Attempt to "solve" a subtype assertion ty_sub <: ty_super.
245 * Return a proposition that is equivalent, but simpler, than
246 * the original assertion. Fail with Unsat error_function if
247 * the assertion is unsatisfiable. Some examples:
248 * string <: arraykey ==> True (represented as Conj [])
249 * (For covariant C and a type variable v)
250 * C<string> <: C<v> ==> string <: v
251 * (Assuming that C does *not* implement interface J)
252 * C <: J ==> Unsat _
253 * (Assuming we have T <: D in tpenv, and class D implements I)
254 * vec<T> <: vec<I> ==> True
255 * This last one would be left as T <: I if seen_generic_params is None
257 and simplify_subtype
258 ~(seen_generic_params : SSet.t option)
259 ~(no_top_bottom : bool)
260 ?(this_ty : locl ty option = None)
261 (ty_sub : locl ty)
262 (ty_super : locl ty)
263 ~(on_error : Errors.typing_error_callback)
264 env : Env.env * TL.subtype_prop =
265 log_subtype ~level:2 ~this_ty ~function_name:"simplify_subtype" env ty_sub ty_super;
266 let env, ety_super = Env.expand_type env ty_super in
267 let env, ety_sub = Env.expand_type env ty_sub in
268 let fail () =
269 TUtils.uerror
271 (fst ety_super)
272 (snd ety_super)
273 (fst ety_sub)
274 (snd ety_sub)
275 on_error in
276 let (|||) (env, p1) (f : Env.env -> Env.env * TL.subtype_prop) =
277 if TL.is_valid p1
278 then env, p1
279 else
280 let env, p2 = f env in
281 env, TL.disj ~fail p1 p2 in
282 (* We *know* that the assertion is unsatisfiable *)
283 let invalid_with f = env, TL.invalid ~fail:f in
284 let invalid () = invalid_with fail in
285 let invalid_env_with env f = env, TL.invalid ~fail:f in
286 let invalid_env env = invalid_env_with env fail in
287 (* We *know* that the assertion is valid *)
288 let valid () = env, TL.valid in
289 (* We don't know whether the assertion is valid or not *)
290 let default () = env, TL.IsSubtype (ety_sub, ety_super) in
291 let simplify_subtype = simplify_subtype ~no_top_bottom ~on_error in
292 let simplify_subtype_funs = simplify_subtype_funs ~no_top_bottom in
293 let simplify_subtype_variance = simplify_subtype_variance ~no_top_bottom ~on_error in
294 let simplify_subtype_generic_sub name_sub opt_sub_cstr ty_super env =
295 begin match seen_generic_params with
296 | None -> default ()
297 | Some seen ->
298 (* If we've seen this type parameter before then we must have gone
299 * round a cycle so we fail
301 if SSet.mem name_sub seen
302 then invalid ()
303 else
304 (* If the generic is actually an expression dependent type,
305 we need to update this_ty
307 let this_ty = if AbstractKind.is_generic_dep_ty name_sub &&
308 Option.is_none this_ty then Some ety_sub else this_ty in
309 let seen_generic_params = Some (SSet.add name_sub seen) in
310 (* Otherwise, we collect all the upper bounds ("as" constraints) on
311 the generic parameter, and check each of these in turn against
312 ty_super until one of them succeeds
314 let rec try_bounds tyl env =
315 match tyl with
316 | [] ->
317 (* Try an implicit mixed = ?nonnull bound before giving up.
318 This can be useful when checking T <: t, where type t is
319 equivalent to but syntactically different from ?nonnull.
320 E.g., if t is a generic type parameter T with nonnull as
321 a lower bound.
323 let r = Reason.Rimplicit_upper_bound (Reason.to_pos (fst ety_sub), "?nonnull") in
324 let tmixed = MakeType.mixed r in
325 env |>
326 simplify_subtype ~seen_generic_params ~this_ty tmixed ty_super
328 | [ty] ->
329 env |>
330 simplify_subtype ~seen_generic_params ~this_ty ty ty_super
332 | ty::tyl ->
333 env |>
334 try_bounds tyl |||
335 simplify_subtype ~seen_generic_params ~this_ty ty ty_super
337 env |>
338 try_bounds (Option.to_list opt_sub_cstr
339 @ Typing_set.elements (Env.get_upper_bounds env name_sub)) |>
340 (* Turn error into a generic error about the type parameter *)
341 if_unsat invalid
342 end in
344 let simplify_subtype_generic_super ty_sub name_super env =
345 begin match seen_generic_params with
346 | None -> default ()
347 | Some seen ->
349 (* If we've seen this type parameter before then we must have gone
350 * round a cycle so we fail
352 if SSet.mem name_super seen
353 then invalid ()
354 else
355 let seen_generic_params = Some (SSet.add name_super seen) in
356 (* Collect all the lower bounds ("super" constraints) on the
357 * generic parameter, and check ty_sub against each of them in turn
358 * until one of them succeeds *)
359 let rec try_bounds tyl env =
360 match tyl with
361 | [] ->
362 invalid ()
364 | ty::tyl ->
365 env |>
366 simplify_subtype ~seen_generic_params ~this_ty ty_sub ty |||
367 try_bounds tyl
369 (* Turn error into a generic error about the type parameter *)
370 env |>
371 try_bounds (Typing_set.elements (Env.get_lower_bounds env name_super)) |>
372 if_unsat invalid
373 end in
374 let has_lower_bounds id =
375 let class_def = Env.get_class env id in
376 match class_def with
377 | Some class_ty ->
378 not (Sequence.is_empty (Cls.lower_bounds_on_this class_ty))
379 | None -> false
382 match snd ety_sub, snd ety_super with
383 | Tvar var_sub, Tvar var_super when var_sub = var_super -> valid ()
385 (* Internally, newtypes and dependent types are always equipped with an upper bound.
386 * In the case when no upper bound is specified in source code,
387 * an implicit upper bound mixed = ?nonnull is added.
389 | Tabstract ((AKnewtype _ | AKdependent _), None), _
390 | _, Tabstract ((AKnewtype _ | AKdependent _), None) -> assert false
392 | (Tprim Nast.(Tint | Tbool | Tfloat | Tstring | Tresource | Tnum |
393 Tarraykey | Tnoreturn) |
394 Tnonnull | Tfun _ | Ttuple _ | Tshape _ |
395 Tanon _ | Tobject | Tclass _ | Tarraykind _),
396 Tnonnull ->
397 valid ()
398 | (Tdynamic | Toption _ | Tprim Nast.(Tnull | Tvoid)),
399 Tnonnull ->
400 invalid ()
402 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tnonnull ->
403 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
405 | Tdynamic, Tdynamic ->
406 valid ()
407 | (Tnonnull | Toption _ | Tprim _ | Tfun _ | Ttuple _ | Tshape _ |
408 Tanon _ | Tobject | Tclass _ | Tarraykind _),
409 Tdynamic ->
410 invalid ()
411 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tdynamic ->
412 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
414 (* everything subtypes mixed *)
415 | _, Toption (_, Tnonnull) -> valid ()
416 (* null is the type of null and is a subtype of any option type. *)
417 | Tprim Nast.Tnull, Toption _ -> valid ()
418 (* void behaves with respect to subtyping as an abstract type with
419 * an implicit upper bound ?nonnull
421 | Tprim Nast.Tvoid, Toption ty_super' ->
422 let r = Reason.Rimplicit_upper_bound (Reason.to_pos (fst ety_sub), "?nonnull") in
423 let tmixed = MakeType.mixed r in
424 env |>
425 simplify_subtype ~seen_generic_params ~this_ty ty_sub ty_super' |||
426 simplify_subtype ~seen_generic_params ~this_ty tmixed ty_super
427 | Tdynamic, Toption ty_super ->
428 simplify_subtype ~seen_generic_params ~this_ty ty_sub ty_super env
429 (* ?ty_sub' <: ?ty_super' iff ty_sub' <: ?ty_super'. Reasoning:
430 * If ?ty_sub' <: ?ty_super', then from ty_sub' <: ?ty_sub' (widening) and transitivity
431 * of <: it follows that ty_sub' <: ?ty_super'. Conversely, if ty_sub' <: ?ty_super', then
432 * by covariance and idempotence of ?, we have ?ty_sub' <: ??ty_sub' <: ?ty_super'.
433 * Therefore, this step preserves the set of solutions.
435 | Toption ty_sub', Toption _ ->
436 simplify_subtype ~seen_generic_params ~this_ty ty_sub' ty_super env
437 (* If ty_sub <: ?ty_super' and ty_sub does not contain null then we
438 * must also have ty_sub <: ty_super'. The converse follows by
439 * widening and transitivity. Therefore, this step preserves the set
440 * of solutions.
442 | (Tprim Nast.(Tint | Tbool | Tfloat | Tstring | Tresource | Tnum |
443 Tarraykey | Tnoreturn) |
444 Tnonnull | Tfun _ | Ttuple _ | Tshape _ | Tanon _ | Tobject |
445 Tclass _ | Tarraykind _ | Tany),
446 Toption ty_super' ->
447 simplify_subtype ~seen_generic_params ~this_ty ty_sub ty_super' env
448 | Tabstract (AKnewtype (name_sub, _), _),
449 Toption (_, Tabstract (AKnewtype (name_super, _), _) as ty_super')
450 when name_super = name_sub ->
451 simplify_subtype ~seen_generic_params ~this_ty ty_sub ty_super' env
453 | Tabstract (AKdependent d_sub, Some bound_sub),
454 Tabstract (AKdependent d_super, Some bound_super) ->
455 let this_ty = Option.first_some this_ty (Some ety_sub) in
456 (* Dependent types are identical but bound might be different *)
457 if d_sub = d_super
458 then simplify_subtype ~seen_generic_params ~this_ty bound_sub bound_super env
459 else simplify_subtype ~seen_generic_params ~this_ty bound_sub ty_super env
461 | Tabstract (AKdependent (DTexpr _), Some ty), Toption arg_ty_super ->
462 let this_ty = Option.first_some this_ty (Some ety_sub) in
463 env |>
464 simplify_subtype ~seen_generic_params ~this_ty ty ty_super |||
465 simplify_subtype ~seen_generic_params ~this_ty ty_sub arg_ty_super
467 (* If t1 <: ?t2 and t1 is an abstract type constrained as t1',
468 * then t1 <: t2 or t1' <: ?t2. The converse is obviously
469 * true as well. We can fold the case where t1 is unconstrained
470 * into the case analysis below.
472 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Toption arg_ty_super ->
473 env |>
474 simplify_subtype ~seen_generic_params ~this_ty ty_sub arg_ty_super |||
475 simplify_subtype ~seen_generic_params ~this_ty ty ty_super
476 (* If t1 <: ?t2, where t1 is guaranteed not to contain null, then
477 * t1 <: t2, and the converse is obviously true as well.
479 | Tabstract (AKgeneric name_sub, opt_sub_cstr), Toption arg_ty_super
480 when Option.is_some seen_generic_params ->
481 env |>
482 simplify_subtype ~seen_generic_params ~this_ty ty_sub arg_ty_super |||
483 (* Look up *)
484 simplify_subtype_generic_sub name_sub opt_sub_cstr ty_super
486 | Tprim (Nast.Tint | Nast.Tfloat), Tprim Nast.Tnum -> valid ()
487 | Tprim (Nast.Tint | Nast.Tstring), Tprim Nast.Tarraykey -> valid ()
488 | Tprim p1, Tprim p2 ->
489 if p1 = p2 then valid () else invalid ()
490 | (Tnonnull | Tdynamic | Tfun _ | Ttuple _ | Tshape _ | Tanon _ |
491 Tobject | Tclass _ | Tarraykind _),
492 Tprim _ ->
493 invalid ()
494 | Toption _,
495 Tprim Nast.(Tvoid | Tint | Tbool | Tfloat | Tstring | Tresource | Tnum |
496 Tarraykey | Tnoreturn) ->
497 invalid ()
498 | Toption ty_sub', Tprim Nast.Tnull ->
499 simplify_subtype ~seen_generic_params ~this_ty ty_sub' ty_super env
500 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tprim _ ->
501 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
503 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Ttuple _ | Tshape _ |
504 Tobject | Tclass _ | Tarraykind _), Tfun _ ->
505 invalid ()
506 | Tfun ft_sub, Tfun ft_super ->
507 let r_sub, r_super = fst ety_sub, fst ety_super in
508 simplify_subtype_funs ~seen_generic_params ~check_return:true
509 r_sub ft_sub r_super ft_super on_error env
510 | Tanon (anon_arity, id), Tfun ft ->
511 let r_sub, r_super = fst ety_sub, fst ety_super in
512 begin match Env.get_anonymous env id with
513 | None ->
514 invalid_with (fun () -> Errors.anonymous_recursive_call (Reason.to_pos r_sub))
515 | Some { Env. rx = reactivity; is_coroutine; counter = ftys; typecheck = anon; _ } ->
516 let p_super = Reason.to_pos r_super in
517 let p_sub = Reason.to_pos r_sub in
518 (* Add function type to set of types seen so far *)
519 ftys := TUtils.add_function_type env ety_super !ftys;
520 (env, TL.valid) |>
521 check_with (subtype_reactivity env reactivity ft.ft_reactive
522 || TypecheckerOptions.unsafe_rx (Env.get_tcopt env))
523 (fun () -> Errors.fun_reactivity_mismatch
524 p_super (TUtils.reactivity_to_string env reactivity)
525 p_sub (TUtils.reactivity_to_string env ft.ft_reactive)) |>
526 check_with (is_coroutine = ft.ft_is_coroutine) (fun () ->
527 Errors.coroutinness_mismatch ft.ft_is_coroutine p_super p_sub) |>
528 check_with (Unify.unify_arities
529 ~ellipsis_is_variadic:true anon_arity ft.ft_arity)
530 (fun () -> Errors.fun_arity_mismatch p_super p_sub) |>
531 (fun (env, prop) ->
532 let env, _, ret = anon env ft.ft_params ft.ft_arity in
533 (env, prop) &&&
534 simplify_subtype ~seen_generic_params ~this_ty ret ft.ft_ret)
536 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tfun _ ->
537 let this_ty = Option.first_some this_ty (Some ety_sub) in
538 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
540 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Tfun _ | Tshape _ |
541 Tanon _ | Tobject | Tclass _ | Tarraykind _),
542 Ttuple _ ->
543 invalid ()
544 (* (t1,...,tn) <: (u1,...,un) iff t1<:u1, ... , tn <: un *)
545 | Ttuple tyl_sub, Ttuple tyl_super ->
546 if List.length tyl_super = List.length tyl_sub
547 then
548 wfold_left2 (fun res ty_sub ty_super -> res
549 &&& simplify_subtype ~seen_generic_params ty_sub ty_super)
550 (env, TL.valid) tyl_sub tyl_super
551 else invalid ()
552 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Ttuple _ ->
553 let this_ty = Option.first_some this_ty (Some ety_sub) in
554 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
556 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Tfun _ | Ttuple _ |
557 Tanon _ | Tobject | Tclass _ | Tarraykind _),
558 Tshape _ ->
559 invalid ()
560 | Tshape (shape_kind_sub, fdm_sub), Tshape (shape_kind_super, fdm_super) ->
561 let r_sub, r_super = fst ety_sub, fst ety_super in
563 * shape_field_type A <: shape_field_type B iff:
564 * 1. A is no more optional than B
565 * 2. A's type <: B.type
567 let simplify_subtype_shape_field name res sft_sub sft_super =
568 match sft_sub.sft_optional, sft_super.sft_optional with
569 | _, true | false, false ->
570 res &&& simplify_subtype ~seen_generic_params ~this_ty
571 sft_sub.sft_ty sft_super.sft_ty
572 | true, false ->
573 res |> with_error (fun () ->
574 let printable_name = TUtils.get_printable_shape_field_name name in
575 match fst sft_sub.sft_ty with
576 | Reason.Rmissing_required_field _ ->
577 Errors.missing_field
578 (Reason.to_pos r_sub)
579 (Reason.to_pos r_super)
580 printable_name
581 | _ ->
582 Errors.required_field_is_optional
583 (Reason.to_pos r_sub)
584 (Reason.to_pos r_super)
585 printable_name) in
586 let lookup_shape_field_type name r shape_kind fdm =
587 match ShapeMap.get name fdm with
588 | Some sft -> sft
589 | None ->
590 let printable_name = TUtils.get_printable_shape_field_name name in
591 let sft_ty = match shape_kind with
592 | Closed_shape ->
593 MakeType.nothing (Reason.Rmissing_required_field (Reason.to_pos r, printable_name))
594 | Open_shape ->
595 MakeType.mixed (Reason.Rmissing_optional_field (Reason.to_pos r, printable_name)) in
596 {sft_ty; sft_optional = true} in
597 begin match shape_kind_sub, shape_kind_super with
598 | Open_shape, Closed_shape ->
599 invalid_with (fun () ->
600 Errors.shape_fields_unknown
601 (Reason.to_pos r_sub)
602 (Reason.to_pos r_super))
603 | _, _ ->
604 ShapeSet.fold
605 (fun name res -> simplify_subtype_shape_field name res
606 (lookup_shape_field_type name r_sub shape_kind_sub fdm_sub)
607 (lookup_shape_field_type name r_super shape_kind_super fdm_super))
608 (ShapeSet.of_list (ShapeMap.keys fdm_sub @ ShapeMap.keys fdm_super))
609 (env, TL.valid)
611 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tshape _ ->
612 let this_ty = Option.first_some this_ty (Some ety_sub) in
613 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
615 | Tclass ((_, class_name), _, _), Tabstract (AKnewtype (enum_name, _), _)
616 when Env.is_enum env enum_name && enum_name = class_name -> valid ()
618 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Tfun _ | Ttuple _ | Tshape _ |
619 Tanon _ | Tobject | Tclass _ | Tarraykind _),
620 Tabstract (AKnewtype _, _) ->
621 invalid ()
623 | Tabstract (AKnewtype (e_sub, _), _), Tabstract (AKnewtype (e_super, _), _)
624 when Env.is_enum env e_sub && Env.is_enum env e_super && e_sub = e_super -> valid ()
625 | Tabstract (AKnewtype (name_sub, tyl_sub), _),
626 Tabstract (AKnewtype (name_super, tyl_super), _)
627 when name_super = name_sub ->
628 let td = Env.get_typedef env name_super in
629 begin match td with
630 | Some {td_tparams; _} ->
631 let variancel = List.map td_tparams (fun t -> t.tp_variance) in
632 simplify_subtype_variance ~seen_generic_params name_sub variancel
633 tyl_sub tyl_super env
634 | None ->
635 invalid ()
637 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tabstract (AKnewtype _, _) ->
638 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
641 | _, Tabstract (AKdependent _, Some (_, Tclass ((_, x), _, _) as ty))
642 when is_final_and_not_contravariant env x ->
643 (* For final class C, there is no difference between `this as X` and `X`,
644 * and `expr<#n> as X` and `X`.
645 * But we need to take care with contravariant classes, since we can't
646 * statically guarantee their runtime type.
648 simplify_subtype ~seen_generic_params ~this_ty ty_sub ty env
650 | Tclass _,
651 Tabstract (AKdependent DTthis, Some (_, Tclass ((_, x), _, tyl_super)))
652 when has_lower_bounds x ->
653 let class_def = Env.get_class env x in
654 begin match class_def with
655 | Some class_ty ->
656 let p_super = fst ety_super in
657 let tyl_super =
658 if List.is_empty tyl_super &&
659 not (Partial.should_check_error (Env.get_mode env) 4029)
660 then List.map (Cls.tparams class_ty) (fun _ -> (p_super, Tany))
661 else tyl_super in
662 if List.length (Cls.tparams class_ty) <> List.length tyl_super
663 then
664 invalid_with (fun () ->
665 Errors.expected_tparam ~definition_pos:(Cls.pos class_ty)
666 ~use_pos:(Reason.to_pos p_super) (List.length (Cls.tparams class_ty)))
667 else
668 let ety_env =
670 type_expansions = [];
671 substs = Subst.make (Cls.tparams class_ty) tyl_super;
672 this_ty = Option.value this_ty ~default:ty_super;
673 from_class = None;
674 validate_dty = None;
675 } in
676 let lower_bounds_super = Cls.lower_bounds_on_this class_ty in
677 let rec try_constraints lower_bounds_super env =
678 match Sequence.next lower_bounds_super with
679 | None -> invalid_env env
680 | Some (ty_super, lower_bounds_super) ->
681 let env, ty_super = Phase.localize ~ety_env env ty_super in
682 env |>
683 simplify_subtype ~seen_generic_params ~this_ty
684 ty_sub ty_super
685 ||| try_constraints lower_bounds_super in
686 try_constraints lower_bounds_super env
687 | None -> invalid ()
689 (* Primitives and other concrete types cannot be subtypes of dependent types *)
690 | (Tnonnull | Tdynamic | Tprim _ | Tfun _ | Ttuple _ | Tshape _ |
691 Tanon _ | Tclass _ | Tobject | Tarraykind _),
692 Tabstract (AKdependent expr_dep, tyopt) ->
693 (* If the bound is the same class try and show more explanation of the error *)
694 begin match snd ty_sub, tyopt with
695 | Tclass ((_, y), _, _), Some (_, (Tclass ((_, x) as id, _, _))) when y = x ->
696 invalid_with (fun () ->
697 Errors.try_ fail
698 (fun error ->
699 let p = Reason.to_pos (fst ety_sub) in
700 if expr_dep = DTcls x
701 then Errors.exact_class_final id p error
702 else Errors.this_final id p error))
703 | _ -> invalid ()
706 | Tabstract (AKnewtype _, Some ty), Tabstract (AKdependent _, _) ->
707 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
708 | Toption _, Tabstract (AKdependent _, Some _) ->
709 invalid ()
711 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Ttuple _ | Tshape _ |
712 Tobject | Tclass _ | Tarraykind _),
713 Tanon _ ->
714 invalid ()
715 | Tanon (_, id1), Tanon (_, id2) -> if id1 = id2 then valid () else invalid ()
716 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tanon _ ->
717 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
718 | Tfun _, Tanon _ ->
719 invalid ()
721 | Tobject, Tobject -> valid ()
722 (* Any class type is a subtype of object *)
723 | Tclass _, Tobject -> valid ()
724 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Tfun _ | Ttuple _ | Tshape _ |
725 Tanon _ | Tarraykind _),
726 Tobject ->
727 invalid ()
728 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tobject ->
729 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
731 | Tabstract (AKnewtype (cid, _), _), Tclass ((_, class_name), _, [ty_super'])
732 when Env.is_enum env cid && class_name = SN.Classes.cHH_BuiltinEnum ->
733 env |>
734 simplify_subtype ~seen_generic_params ~this_ty ty_sub ty_super' &&&
735 simplify_subtype ~seen_generic_params ~this_ty ty_super' ty_sub
736 | Tabstract (AKnewtype (enum_name, _), _), Tclass ((_, class_name), Nonexact, _)
737 when (Env.is_enum env enum_name && enum_name = class_name || class_name = SN.Classes.cXHPChild) ->
738 valid ()
739 | Tabstract (AKnewtype (enum_name, _), Some ty), Tclass ((_, class_name), exact, _)
740 when Env.is_enum env enum_name ->
741 if enum_name = class_name && exact = Nonexact
742 then valid ()
743 else simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
744 | Tprim Nast.Tstring, Tclass ((_, class_name), exact, _) ->
745 if (class_name = SN.Classes.cStringish || class_name = SN.Classes.cXHPChild)
746 && exact = Nonexact
747 then valid ()
748 else invalid ()
749 | Tprim Nast.(Tarraykey | Tint | Tfloat | Tnum), Tclass ((_, class_name), exact, _) ->
750 if class_name = SN.Classes.cXHPChild && exact = Nonexact then valid () else invalid ()
751 | (Tnonnull | Tdynamic | Tprim Nast.(Tnull | Tvoid | Tbool | Tresource | Tnoreturn) |
752 Toption _ | Tfun _ | Ttuple _ | Tshape _ | Tanon _),
753 Tclass _ ->
754 invalid ()
755 (* Match what's done in unify for non-strict code *)
756 | Tobject, Tclass _ ->
757 if Partial.should_check_error (Env.get_mode env) 4110 then invalid () else valid ()
758 | Tclass (x_sub, exact_sub, tyl_sub), Tclass (x_super, exact_super, tyl_super) ->
759 let exact_match =
760 match exact_sub, exact_super with
761 | Nonexact, Exact -> false
762 | _, _ -> true in
763 let p_sub, p_super = fst ety_sub, fst ety_super in
764 let cid_super, cid_sub = (snd x_super), (snd x_sub) in
765 (* This is side-effecting as it registers a dependency *)
766 let class_def_sub = Env.get_class env cid_sub in
767 if cid_super = cid_sub
768 then
769 (* If class is final then exactness is superfluous *)
770 let is_final =
771 match class_def_sub with
772 | Some tc -> Cls.final tc
773 | None -> false in
774 if not (exact_match || is_final)
775 then invalid ()
776 else
777 (* We handle the case where a generic A<T> is used as A *)
778 let tyl_super =
779 if List.is_empty tyl_super &&
780 not (Partial.should_check_error (Env.get_mode env) 4101)
781 then List.map tyl_sub (fun _ -> (p_super, Tany))
782 else tyl_super in
783 let tyl_sub =
784 if List.is_empty tyl_sub &&
785 not (Partial.should_check_error (Env.get_mode env) 4101)
786 then List.map tyl_super (fun _ -> (p_super, Tany))
787 else tyl_sub in
788 if List.length tyl_sub <> List.length tyl_super
789 then begin
790 let n_sub = String_utils.soi (List.length tyl_sub) in
791 let n_super = String_utils.soi (List.length tyl_super) in
792 invalid_with (fun () ->
793 Errors.type_arity_mismatch (fst x_super) n_super (fst x_sub) n_sub)
795 else
796 if List.is_empty tyl_sub && List.is_empty tyl_super
797 then valid ()
798 else
799 let variancel =
800 match class_def_sub with
801 | None ->
802 List.map tyl_sub (fun _ -> Ast_defs.Invariant)
803 | Some class_sub ->
804 List.map (Cls.tparams class_sub) (fun t -> t.tp_variance) in
806 (* C<t1, .., tn> <: C<u1, .., un> iff
807 * t1 <:v1> u1 /\ ... /\ tn <:vn> un
808 * where vi is the variance of the i'th generic parameter of C,
809 * and <:v denotes the appropriate direction of subtyping for variance v
811 simplify_subtype_variance ~seen_generic_params cid_sub variancel tyl_sub
812 tyl_super env
813 else
814 if not exact_match
815 then invalid ()
816 else
817 begin match class_def_sub with
818 | None ->
819 (* This should have been caught already in the naming phase *)
820 valid ()
822 | Some class_sub ->
823 (* We handle the case where a generic A<T> is used as A *)
824 let tyl_sub =
825 if List.is_empty tyl_sub &&
826 not (Partial.should_check_error (Env.get_mode env) 4029)
827 then List.map (Cls.tparams class_sub) (fun _ -> (p_sub, Tany))
828 else tyl_sub in
829 if List.length (Cls.tparams class_sub) <> List.length tyl_sub
830 then
831 invalid_with (fun () ->
832 Errors.expected_tparam ~definition_pos:(Cls.pos class_sub)
833 ~use_pos:(Reason.to_pos p_sub) (List.length (Cls.tparams class_sub)))
834 else
835 let ety_env =
837 type_expansions = [];
838 substs = Subst.make (Cls.tparams class_sub) tyl_sub;
839 (* TODO: do we need this? *)
840 this_ty = Option.value this_ty ~default:ty_sub;
841 from_class = None;
842 validate_dty = None;
843 } in
844 let up_obj = Cls.get_ancestor class_sub cid_super in
845 match up_obj with
846 | Some up_obj ->
847 let env, up_obj = Phase.localize ~ety_env env up_obj in
848 simplify_subtype ~seen_generic_params ~this_ty up_obj ty_super env
849 | None ->
850 if Cls.kind class_sub = Ast_defs.Ctrait || Cls.kind class_sub = Ast_defs.Cinterface then
851 let rec try_upper_bounds_on_this up_objs env =
852 match Sequence.next up_objs with
853 | None ->
854 (* It's crucial that we don't lose updates to global_tpenv in env that were
855 * introduced by PHase.localize. TODO: avoid this requirement *)
856 invalid_env env
858 | Some (ub_obj_typ, up_objs) ->
860 (* a trait is never the runtime type, but it can be used
861 * as a constraint if it has requirements or where constraints
862 * for its using classes *)
863 let env, ub_obj_typ = Phase.localize ~ety_env env ub_obj_typ in
864 env |>
865 simplify_subtype ~seen_generic_params ~this_ty
866 (p_sub, snd ub_obj_typ) ty_super
867 ||| try_upper_bounds_on_this up_objs
869 try_upper_bounds_on_this (Cls.upper_bounds_on_this class_sub) env
870 else invalid ()
872 | Tabstract ((AKnewtype _), Some ty), Tclass _ ->
873 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
874 | Tarraykind _, Tclass ((_, class_name), Nonexact, _)
875 when class_name = SN.Classes.cXHPChild -> valid ()
876 | Tarraykind akind, Tclass ((_, coll), Nonexact, [tv_super])
877 when (coll = SN.Collections.cTraversable ||
878 coll = SN.Rx.cTraversable ||
879 coll = SN.Collections.cContainer) ->
880 (match akind with
881 (* array <: Traversable<_> and emptyarray <: Traversable<t> for any t *)
882 | AKany ->
883 simplify_subtype ~seen_generic_params ~this_ty
884 (fst ety_sub, Tany) tv_super env
885 | AKempty -> valid ()
886 (* vec<tv> <: Traversable<tv_super>
887 * iff tv <: tv_super
888 * Likewise for vec<tv> <: Container<tv_super>
889 * and map<_,tv> <: Traversable<tv_super>
890 * and map<_,tv> <: Container<tv_super>
892 | AKvarray tv
893 | AKvec tv
894 | AKdarray (_, tv)
895 | AKvarray_or_darray tv
896 | AKmap (_, tv) ->
897 simplify_subtype ~seen_generic_params ~this_ty tv tv_super env
899 | Tarraykind akind, Tclass ((_, coll), Nonexact, [tk_super; tv_super])
900 when (coll = SN.Collections.cKeyedTraversable
901 || coll = SN.Rx.cKeyedTraversable
902 || coll = SN.Collections.cKeyedContainer) ->
903 let r = fst ety_sub in
904 (match akind with
905 | AKany ->
906 env |>
907 simplify_subtype ~seen_generic_params ~this_ty (fst ety_sub, Tany) tk_super &&&
908 simplify_subtype ~seen_generic_params ~this_ty (fst ety_sub, Tany) tv_super
909 | AKempty -> valid ()
910 | AKvarray tv
911 | AKvec tv ->
912 env |>
913 simplify_subtype ~seen_generic_params ~this_ty (MakeType.int r) tk_super &&&
914 simplify_subtype ~seen_generic_params ~this_ty tv tv_super
915 | AKvarray_or_darray tv ->
916 let tk_sub = MakeType.arraykey (Reason.Rvarray_or_darray_key (Reason.to_pos r)) in
917 env |>
918 simplify_subtype ~seen_generic_params ~this_ty tk_sub tk_super &&&
919 simplify_subtype ~seen_generic_params ~this_ty tv tv_super
920 | AKdarray (tk, tv)
921 | AKmap (tk, tv) ->
922 env |>
923 simplify_subtype ~seen_generic_params ~this_ty tk tk_super &&&
924 simplify_subtype ~seen_generic_params ~this_ty tv tv_super
926 | Tarraykind _, Tclass ((_, coll), Nonexact, [])
927 when (coll = SN.Collections.cKeyedTraversable ||
928 coll = SN.Rx.cKeyedTraversable ||
929 coll = SN.Collections.cKeyedContainer) ->
930 (* All arrays are subtypes of the untyped KeyedContainer / Traversables *)
931 valid ()
932 | Tarraykind _, Tclass _ -> invalid ()
933 | Tabstract (AKdependent _, Some ty), Tclass _ ->
934 let this_ty = Option.first_some this_ty (Some ety_sub) in
935 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
937 (* Arrays *)
938 | Ttuple _, Tarraykind AKany ->
939 if TypecheckerOptions.disallow_array_as_tuple (Env.get_tcopt env)
940 then invalid ()
941 else valid ()
942 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Tfun _ | Ttuple _ |
943 Tshape _ | Tanon _ | Tobject | Tclass _),
944 Tarraykind _ ->
945 invalid ()
946 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tarraykind _ ->
947 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
948 | Tarraykind ak_sub, Tarraykind ak_super ->
949 let r = fst ety_sub in
950 begin match ak_sub, ak_super with
951 (* An array of any kind is a subtype of an array of AKany *)
952 | _, AKany ->
953 valid ()
955 (* An empty array is a subtype of any array type *)
956 | AKempty, _ ->
957 valid ()
959 (* array is a subtype of varray_or_darray<_> *)
960 | AKany, AKvarray_or_darray (_, Tany) ->
961 valid ()
963 | AKany, _ ->
964 let safe_array = TypecheckerOptions.safe_array (Env.get_tcopt env) in
965 if safe_array then invalid () else valid ()
967 (* varray_or_darray<ty1> <: varray_or_darray<ty2> iff t1 <: ty2
968 But, varray_or_darray<ty1> is never a subtype of a vect-like array *)
969 | AKvarray_or_darray ty_sub, AKvarray_or_darray ty_super ->
970 simplify_subtype ~seen_generic_params ~this_ty ty_sub ty_super env
972 | (AKvarray ty_sub | AKvec ty_sub),
973 (AKvarray ty_super | AKvec ty_super | AKvarray_or_darray ty_super) ->
974 simplify_subtype ~seen_generic_params ~this_ty ty_sub ty_super env
976 | (AKdarray (tk_sub, tv_sub) | AKmap (tk_sub, tv_sub)),
977 (AKdarray (tk_super, tv_super) | AKmap (tk_super, tv_super)) ->
978 env |>
979 simplify_subtype ~seen_generic_params ~this_ty tk_sub tk_super &&&
980 simplify_subtype ~seen_generic_params ~this_ty tv_sub tv_super
982 | (AKdarray (tk_sub, tv_sub) | AKmap (tk_sub, tv_sub)),
983 (AKvarray_or_darray tv_super) ->
984 let tk_super = MakeType.arraykey (Reason.Rvarray_or_darray_key (Reason.to_pos (fst ety_super))) in
985 env |>
986 simplify_subtype ~seen_generic_params ~this_ty tk_sub tk_super &&&
987 simplify_subtype ~seen_generic_params ~this_ty tv_sub tv_super
989 | (AKvarray elt_ty | AKvec elt_ty), (AKdarray _ | AKmap _)
990 when not (TypecheckerOptions.safe_vector_array (Env.get_tcopt env)) ->
991 let int_reason = Reason.Ridx (Reason.to_pos r, Reason.Rnone) in
992 let int_type = MakeType.int int_reason in
993 simplify_subtype ~seen_generic_params ~this_ty
994 (r, Tarraykind (AKmap (int_type, elt_ty))) ty_super env
996 (* any other array subtyping is unsatisfiable *)
997 | _ ->
998 invalid ()
1001 (* ty_sub <: union{ty_super'} iff ty_sub <: ty_super' *)
1002 | _, Tunion [ty_super'] ->
1003 simplify_subtype ~seen_generic_params ~this_ty ty_sub ty_super' env
1005 (* t1 | ... | tn <: t
1006 * if and only if
1007 * t1 <: t /\ ... /\ tn <: t
1008 * We want this even if t is a type variable e.g. consider
1009 * int | v <: v
1011 | Tunion tyl, _->
1012 List.fold_left tyl ~init:(env, TL.valid) ~f:(fun res ty_sub ->
1013 res &&& simplify_subtype ~seen_generic_params ty_sub ty_super)
1015 (* t <: (t1 & ... & tn)
1016 * if and only if
1017 * t <: t1 /\ ... /\ t <: tn
1019 | _, Tintersection tyl ->
1020 List.fold_left tyl ~init:(env, TL.valid) ~f:(fun res ty_super ->
1021 res &&& simplify_subtype ~seen_generic_params ~this_ty ty_sub ty_super)
1023 (* We want to treat nullable as a union with the same rule as above.
1024 * This is only needed for Tvar on right; other cases are dealt with specially as
1025 * derived rules.
1027 | Toption t, Tvar _ ->
1028 env |>
1029 simplify_subtype ~seen_generic_params ~this_ty t ty_super &&&
1030 simplify_subtype ~seen_generic_params ~this_ty (MakeType.null (fst ety_sub)) ty_super
1032 | Terr, Terr -> valid ()
1033 | Terr, _ | _, Terr -> if no_top_bottom then default () else valid ()
1035 | Tvar _, _ | _, Tvar _ ->
1036 default ()
1038 (* A & B <: C iif A <: C | !B *)
1039 | Tintersection tyl, _
1040 when let _, non_ty_opt, _ = find_type_with_exact_negation env tyl in
1041 Option.is_some non_ty_opt ->
1042 let env, non_ty_opt, tyl' = find_type_with_exact_negation env tyl in
1043 let non_ty = Option.value_exn non_ty_opt in
1044 let env, ty_super' = TUtils.union env ty_super non_ty in
1045 let ty_sub' = MakeType.intersection (fst ety_sub) tyl' in
1046 simplify_subtype ~seen_generic_params ty_sub' ty_super' env
1048 (* A <: ?B iif A & nonnull <: B
1049 Only apply if B is a type variable or an intersection, to avoid oscillating
1050 forever between this case and the previous one.*)
1051 | _, Toption ty_super'
1052 when let _, (_, ety_super') = Env.expand_type env ty_super' in
1053 match ety_super' with
1054 | Tintersection _ | Tvar _ -> true
1055 | _ -> false ->
1056 let env, ty_sub' = let r = fst ety_super in Inter.intersect env r ety_sub (MakeType.nonnull r) in
1057 simplify_subtype ~seen_generic_params ty_sub' ty_super' env
1059 (* If subtype and supertype are the same generic parameter, we're done *)
1060 | Tabstract (AKgeneric name_sub, _), Tabstract (AKgeneric name_super, _)
1061 when name_sub = name_super ->
1062 valid ()
1064 (* When decomposing subtypes for the purpose of adding bounds on generic
1065 * parameters to the context, (so seen_generic_params = None), leave
1066 * subtype so that the bounds get added *)
1067 | Tabstract (AKgeneric _, _), _
1068 | _, Tabstract (AKgeneric _, _)
1069 when Option.is_none seen_generic_params ->
1070 default ()
1072 (* Num is not atomic: it is equivalent to int|float. The rule below relies
1073 * on ty_sub not being a union e.g. consider num <: arraykey | float, so
1074 * we break out num first.
1076 | Tprim Nast.Tnum, Tunion _ ->
1077 let r = fst ty_sub in
1078 env |>
1079 simplify_subtype ~seen_generic_params ~this_ty (MakeType.float r) ty_super &&&
1080 simplify_subtype ~seen_generic_params ~this_ty (MakeType.int r) ty_super
1082 (* Likewise, reduce nullable on left to a union *)
1083 | Toption ty, Tunion _ ->
1084 let r = fst ty_sub in
1085 let env, p1 =
1086 simplify_subtype ~seen_generic_params ~this_ty (MakeType.null r) ty_super env in
1087 if TL.is_unsat p1
1088 then invalid ()
1089 else
1090 let env, p2 = simplify_subtype ~seen_generic_params ~this_ty ty ty_super env in
1091 env, TL.conj p1 p2
1093 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tunion [] ->
1094 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
1096 | Tabstract (AKgeneric name_sub, opt_sub_cstr), Tunion [] ->
1097 simplify_subtype_generic_sub name_sub opt_sub_cstr ty_super env
1098 | (Tnonnull | Tdynamic | Tprim _ | Tfun _ | Ttuple _ | Tshape _ |
1099 Tanon _ | Tobject | Tclass _ | Tarraykind _),
1100 Tunion [] ->
1101 invalid ()
1103 | _, Tunion (_ :: _ as tyl) ->
1104 (* It's sound to reduce t <: t1 | t2 to (t <: t1) || (t <: t2). But
1105 * not complete e.g. consider (t1 | t3) <: (t1 | t2) | (t2 | t3).
1106 * But we deal with unions on the left first (see case above), so this
1107 * particular situation won't arise.
1108 * TODO: identify under what circumstances this reduction is complete.
1110 let rec try_each tys env =
1111 match tys with
1112 | [] ->
1113 (* If type on left might have an explicit upper bound (e.g. generic parameters, new type)
1114 * then we'd better check this too. e.g. consider foo<T as ~int> and T <: ~num
1116 begin match snd ty_sub with
1117 | Tabstract ((AKnewtype _ | AKdependent _), Some ty) ->
1118 simplify_subtype ~seen_generic_params ~this_ty ty ty_super env
1119 | Tabstract (AKgeneric name_sub, opt_sub_cstr) ->
1120 simplify_subtype_generic_sub name_sub opt_sub_cstr ty_super env
1121 | _ ->
1122 invalid ()
1124 | ty::tys ->
1125 env |>
1126 simplify_subtype ~seen_generic_params ~this_ty ty_sub ty
1127 ||| try_each tys
1129 try_each tyl env
1131 (* It's sound to reduce t1 & t2 <: t to (t1 <: t) || (t2 <: t), but
1132 * not complete.
1134 | Tintersection tyl, _ ->
1135 List.fold_left tyl ~init:(env, TL.invalid ~fail) ~f:(fun res ty_sub ->
1136 res ||| simplify_subtype ~seen_generic_params ~this_ty ty_sub ty_super)
1138 | Ttuple tyl, Tdestructure tyl_dest ->
1139 if List.length tyl <> List.length tyl_dest then invalid () else
1140 List.fold2_exn tyl tyl_dest ~init:(env, TL.valid) ~f:(fun res ty ty_dest ->
1141 res &&& simplify_subtype ~seen_generic_params ~this_ty ty ty_dest)
1142 | Tclass ((_, x), _, [elt_type]), Tdestructure tyl_dest
1143 when x = SN.Collections.cVector
1144 || x = SN.Collections.cImmVector
1145 || x = SN.Collections.cVec
1146 || x = SN.Collections.cConstVector ->
1147 List.fold tyl_dest ~init:(env, TL.valid) ~f:(fun res ty_dest ->
1148 res &&& simplify_subtype ~seen_generic_params ~this_ty elt_type ty_dest)
1149 | Tclass ((_, x), _, tyl), Tdestructure tyl_dest when x = SN.Collections.cPair ->
1150 if List.length tyl <> List.length tyl_dest then invalid () else
1151 List.fold2_exn tyl tyl_dest ~init:(env, TL.valid) ~f:(fun res ty ty_dest ->
1152 res &&& simplify_subtype ~seen_generic_params ~this_ty ty ty_dest)
1153 | Tarraykind (AKvec elt_type), Tdestructure tyl_dest
1154 | Tarraykind (AKvarray elt_type), Tdestructure tyl_dest ->
1155 List.fold tyl_dest ~init:(env, TL.valid) ~f:(fun res ty_dest ->
1156 res &&& simplify_subtype ~seen_generic_params ~this_ty elt_type ty_dest)
1157 | Tdynamic, Tdestructure tyl_dest ->
1158 List.fold tyl_dest ~init:(env, TL.valid) ~f:(fun res ty_dest ->
1159 res &&& simplify_subtype ~seen_generic_params ~this_ty ty_sub ty_dest)
1160 (* TODO: should remove these any cases *)
1161 | Tarraykind (AKany | AKempty), Tdestructure tyl_dest
1162 | Tany, Tdestructure tyl_dest ->
1163 let any = (fst ty_super, Tany) in
1164 List.fold tyl_dest ~init:(env, TL.valid) ~f:(fun res ty_dest ->
1165 res &&& simplify_subtype ~seen_generic_params ~this_ty any ty_dest)
1167 | Tany, Tany ->
1168 valid ()
1170 (* If ty_sub contains other types, e.g. C<T>, make this a subtype assertion on
1171 those inner types and `any`. For example transform the assertion
1172 C<D> <: Tany
1173 into
1174 C<D> <: C<Tany>
1175 which might become
1176 D <: Tany
1177 if say C is covariant.
1179 | _, Tany ->
1180 if no_top_bottom then default () else
1181 let ety_super = anyfy env (fst ety_super) ety_sub in
1182 simplify_subtype ~seen_generic_params ~this_ty ety_sub ety_super env
1184 | Tany, _ ->
1185 if no_top_bottom then default () else
1186 let ety_sub = anyfy env (fst ety_sub) ety_super in
1187 simplify_subtype ~seen_generic_params ~this_ty ety_sub ety_super env
1189 (* Supertype is generic parameter *and* subtype is a newtype with bound.
1190 * We need to make this a special case because there is a *choice*
1191 * of subtyping rule to apply. See details in the case of dependent type
1192 * against generic parameter which is similar
1194 | Tabstract (AKnewtype (_, _), Some ty), Tabstract (AKgeneric name_super, _)
1195 when Option.is_some seen_generic_params ->
1196 env |>
1197 simplify_subtype ~seen_generic_params ~this_ty ty ty_super |||
1198 simplify_subtype_generic_super ty_sub name_super
1200 (* void behaves with respect to subtyping as an abstract type with
1201 * an implicit upper bound ?nonnull
1203 | Tprim Nast.Tvoid, Tabstract (AKgeneric name_super, _)
1204 when Option.is_some seen_generic_params ->
1205 let r = Reason.Rimplicit_upper_bound (Reason.to_pos (fst ety_sub), "?nonnull") in
1206 let tmixed = (r, Toption (r, Tnonnull)) in
1207 env |>
1208 simplify_subtype ~seen_generic_params ~this_ty tmixed ty_super |||
1209 simplify_subtype_generic_super ty_sub name_super
1211 (* Supertype is generic parameter *and* subtype is dependent.
1212 * We need to make this a special case because there is a *choice*
1213 * of subtyping rule to apply.
1215 * Example. First suppose that we have the definition
1217 * abstract const type TC as C
1219 * (1) Now suppose we have to check
1220 * this::TC <: Tu
1221 * where we have the constraint
1222 * <Tu super C>.
1223 * Then it's necessary to apply the rule for AKdependent first, so we
1224 * reduce this problem to
1225 * C <: Tu
1226 * and then call sub_generic_params to deal with the type parameter.
1227 * (2) Alternatively, suppose we again have to check
1228 * this::TC <: Tu
1229 * but this time we have the constraint
1230 * <Tu super this::TC>.
1231 * Then if we first reduce the problem to C <: Tu we fail;
1232 * but if we also try sub_generic_params then we succeed, because
1233 * we end up checking this::TC <: this::TC.
1235 | Tabstract (AKdependent _, Some ty), Tabstract (AKgeneric name_super, _)
1236 when Option.is_some seen_generic_params ->
1237 env |>
1238 simplify_subtype_generic_super ty_sub name_super |||
1239 (let this_ty = Option.first_some this_ty (Some ety_sub) in
1240 simplify_subtype ~seen_generic_params ~this_ty ty ty_super)
1242 (* Subtype or supertype is generic parameter
1243 * We delegate these cases to a separate function in order to catch cycles
1244 * in constraints e.g. <T1 as T2, T2 as T3, T3 as T1>
1246 | Tabstract (AKgeneric name_sub, opt_sub_cstr), _ ->
1247 simplify_subtype_generic_sub name_sub opt_sub_cstr ty_super env
1249 | _, Tabstract (AKgeneric name_super, _) ->
1250 simplify_subtype_generic_super ty_sub name_super env
1252 | Tdestructure _, _ ->
1253 invalid ()
1254 | _, Tdestructure _ ->
1255 invalid ()
1257 and simplify_subtype_variance
1258 ~(seen_generic_params : SSet.t option)
1259 ~(no_top_bottom : bool)
1260 (cid : string)
1261 (variancel : Ast_defs.variance list)
1262 (children_tyl : locl ty list)
1263 (super_tyl : locl ty list)
1264 ~(on_error : Errors.typing_error_callback)
1265 : Env.env -> Env.env * TL.subtype_prop
1266 = fun env ->
1267 let simplify_subtype = simplify_subtype ~no_top_bottom ~seen_generic_params ~on_error
1268 ~this_ty:None in
1269 let simplify_subtype_variance = simplify_subtype_variance ~no_top_bottom
1270 ~seen_generic_params ~on_error in
1271 match variancel, children_tyl, super_tyl with
1272 | [], _, _
1273 | _, [], _
1274 | _, _, [] -> valid env
1275 | variance :: variancel, child :: childrenl, super :: superl ->
1276 begin match variance with
1277 | Ast_defs.Covariant ->
1278 simplify_subtype child super env
1279 | Ast_defs.Contravariant ->
1280 let super = (Reason.Rcontravariant_generic (fst super,
1281 Utils.strip_ns cid), snd super) in
1282 simplify_subtype super child env
1283 | Ast_defs.Invariant ->
1284 let super' = (Reason.Rinvariant_generic (fst super,
1285 Utils.strip_ns cid), snd super) in
1286 env |>
1287 simplify_subtype child super' &&&
1288 simplify_subtype super' child
1289 end &&&
1290 simplify_subtype_variance cid variancel childrenl superl
1292 and simplify_subtype_params
1293 ~(seen_generic_params : SSet.t option)
1294 ~(no_top_bottom : bool)
1295 ?(is_method : bool = false)
1296 ?(check_params_reactivity = false)
1297 ?(check_params_mutability = false)
1298 (subl : locl fun_param list)
1299 (superl : locl fun_param list)
1300 (variadic_sub_ty : locl ty option)
1301 (variadic_super_ty : locl ty option)
1302 ~(on_error : Errors.typing_error_callback)
1303 env =
1305 let simplify_subtype = simplify_subtype ~seen_generic_params ~no_top_bottom ~on_error in
1306 let simplify_subtype_params = simplify_subtype_params ~seen_generic_params
1307 ~no_top_bottom ~on_error in
1308 let simplify_subtype_params_with_variadic = simplify_subtype_params_with_variadic
1309 ~seen_generic_params ~no_top_bottom in
1310 let simplify_supertype_params_with_variadic = simplify_supertype_params_with_variadic
1311 ~seen_generic_params ~no_top_bottom in
1312 match subl, superl with
1313 (* When either list runs out, we still have to typecheck that
1314 the remaining portion sub/super types with the other's variadic.
1315 For example, if
1316 ChildClass {
1317 public function a(int $x = 0, string ... $args) // superl = [int], super_var = string
1319 overrides
1320 ParentClass {
1321 public function a(string ... $args) // subl = [], sub_var = string
1323 , there should be an error because the first argument will be checked against
1324 int, not string that is, ChildClass::a("hello") would crash,
1325 but ParentClass::a("hello") wouldn't.
1327 Similarly, if the other list is longer, aka
1328 ChildClass extends ParentClass {
1329 public function a(mixed ... $args) // superl = [], super_var = mixed
1331 overrides
1332 ParentClass {
1333 //subl = [string], sub_var = string
1334 public function a(string $x = 0, string ... $args)
1336 It should also check that string is a subtype of mixed.
1338 | [], _ -> (match variadic_super_ty with
1339 | None -> valid env
1340 | Some ty -> simplify_supertype_params_with_variadic superl ty on_error env)
1341 | _, [] -> (match variadic_sub_ty with
1342 | None -> valid env
1343 | Some ty -> simplify_subtype_params_with_variadic subl ty on_error env)
1344 | sub :: subl, super :: superl ->
1345 env |>
1346 begin
1347 if check_params_reactivity
1348 then subtype_fun_params_reactivity sub super
1349 else valid
1350 end &&&
1351 begin
1352 if check_params_mutability
1353 then check_mutability
1354 ~is_receiver:false
1355 sub.fp_pos sub.fp_mutability super.fp_pos super.fp_mutability
1356 else valid
1357 end &&&
1359 fun env ->
1360 begin
1361 let { fp_type = ty_sub; _ } = sub in
1362 let { fp_type = ty_super; _ } = super in
1363 (* Check that the calling conventions of the params are compatible.
1364 * We don't currently raise an error for reffiness because function
1365 * hints don't support '&' annotations (enforce_ctpbr = false). *)
1366 Unify.unify_param_modes ~enforce_ctpbr:is_method sub super;
1367 Unify.unify_accept_disposable sub super;
1368 match sub.fp_kind, super.fp_kind with
1369 | FPinout, FPinout ->
1370 (* Inout parameters are invariant wrt subtyping for function types. *)
1371 env |>
1372 simplify_subtype ty_super ty_sub &&&
1373 simplify_subtype ty_sub ty_super
1374 | _ ->
1375 env |>
1376 simplify_subtype ty_sub ty_super
1377 end &&&
1378 simplify_subtype_params ~is_method subl superl
1379 variadic_sub_ty variadic_super_ty
1381 and simplify_subtype_params_with_variadic
1382 ~(seen_generic_params : SSet.t option)
1383 ~(no_top_bottom : bool)
1384 (subl : locl fun_param list)
1385 (variadic_ty : locl ty)
1386 (on_error : Errors.typing_error_callback)
1387 env =
1388 let simplify_subtype = simplify_subtype ~seen_generic_params ~no_top_bottom ~on_error in
1389 let simplify_subtype_params_with_variadic = simplify_subtype_params_with_variadic
1390 ~seen_generic_params ~no_top_bottom in
1391 match subl with
1392 | [] -> valid env
1393 | { fp_type = sub; _ } :: subl ->
1394 env |>
1395 simplify_subtype sub variadic_ty &&&
1396 simplify_subtype_params_with_variadic subl variadic_ty on_error
1398 and simplify_supertype_params_with_variadic
1399 ~(seen_generic_params : SSet.t option)
1400 ~(no_top_bottom : bool)
1401 (superl : locl fun_param list)
1402 (variadic_ty : locl ty)
1403 (on_error : Errors.typing_error_callback)
1404 env =
1405 let simplify_subtype = simplify_subtype ~seen_generic_params ~no_top_bottom ~on_error in
1406 let simplify_supertype_params_with_variadic = simplify_supertype_params_with_variadic
1407 ~seen_generic_params ~no_top_bottom in
1408 match superl with
1409 | [] -> valid env
1410 | { fp_type = super; _ } :: superl ->
1411 env |>
1412 simplify_subtype variadic_ty super &&&
1413 simplify_supertype_params_with_variadic superl variadic_ty on_error
1415 and subtype_reactivity
1416 ?(extra_info: reactivity_extra_info option)
1417 ?(is_call_site = false)
1418 (env : Env.env)
1419 (r_sub : reactivity)
1420 (r_super : reactivity) : bool =
1422 let maybe_localize t =
1423 match t with
1424 | DeclTy t ->
1425 let ety_env = Phase.env_with_self env in
1426 let _, t = Phase.localize ~ety_env env t in
1428 | LoclTy t -> t in
1430 let class_ty =
1431 Option.bind extra_info (fun { class_ty = cls; _ } ->
1432 Option.map cls ~f:maybe_localize) in
1434 (* for method declarations check if condition type for r_super includes
1435 reactive method with a matching name. If yes - then it will act as a guarantee
1436 that derived class will have to redefine the method with a shape required
1437 by condition type (reactivity of redefined method must be subtype of reactivity
1438 of method in interface) *)
1439 let condition_type_has_matching_reactive_method condition_type_super (method_name, is_static) =
1440 let m =
1441 ConditionTypes.try_get_method_from_condition_type
1442 env condition_type_super is_static method_name in
1443 match m with
1444 | Some { ce_type = lazy (_, Tfun f); _ } ->
1445 (* check that reactivity of interface method (effectively a promised
1446 reactivity of a method in derived class) is a subtype of r_super.
1447 NOTE: we check only for unconditional reactivity since conditional
1448 version does not seems to yield a lot and will requre implementing
1449 cycle detection for condition types *)
1450 begin match f.ft_reactive with
1451 | Reactive None | Shallow None | Local None ->
1452 let extra_info = {
1453 empty_extra_info with parent_class_ty = Some (DeclTy condition_type_super)
1454 } in
1455 subtype_reactivity ~extra_info env f.ft_reactive r_super
1456 | _ -> false
1458 | _ -> false in
1459 match r_sub, r_super, extra_info with
1460 (* anything is a subtype of nonreactive functions *)
1461 | _, Nonreactive, _ -> true
1462 (* to compare two maybe reactive values we need to unwrap them *)
1463 | MaybeReactive sub, MaybeReactive super, _ ->
1464 subtype_reactivity ?extra_info ~is_call_site env sub super
1465 (* for explicit checks at callsites implicitly unwrap maybereactive value:
1466 function f(<<__AtMostRxAsFunc>> F $f)
1467 f(<<__RxLocal>> () ==> {... })
1468 here parameter will be maybereactive and argument - rxlocal
1470 | sub, MaybeReactive super, _ when is_call_site ->
1471 subtype_reactivity ?extra_info ~is_call_site env sub super
1472 (* if is_call_site is falst ignore maybereactive flavors.
1473 This usually happens during subtype checks for arguments and when target
1474 function is conditionally reactive we'll do the proper check
1475 in typing_reactivity.check_call. *)
1476 | _, MaybeReactive _, _ when not is_call_site -> true
1477 (* ok:
1478 class A { function f((function(): int) $f) {} }
1479 class B extends A {
1480 <<__Rx>>
1481 function f(<<__AtMostRxAsFunc>> (function(): int) $f);
1483 reactivity for arguments is checked contravariantly *)
1484 | _, RxVar None, _
1485 (* ok:
1486 <<__Rx>>
1487 function f(<<__AtMostRxAsFunc>> (function(): int) $f) { return $f() } *)
1488 | RxVar None, RxVar _, _ -> true
1489 | RxVar (Some sub), RxVar (Some super), _
1490 | sub, RxVar (Some super), _ ->
1491 subtype_reactivity ?extra_info ~is_call_site env sub super
1492 | RxVar _, _, _ -> false
1493 | (Local cond_sub | Shallow cond_sub | Reactive cond_sub), Local cond_super, _
1494 | (Shallow cond_sub | Reactive cond_sub), Shallow cond_super, _
1495 | Reactive cond_sub, Reactive cond_super, _
1496 when subtype_param_rx_if_impl ~is_param:false env cond_sub class_ty cond_super ->
1497 true
1498 (* function type TSub of method M with arbitrary reactivity in derive class
1499 can be subtype of conditionally reactive function type TSuper of method M
1500 defined in base class when condition type has reactive method M.
1501 interface Rx {
1502 <<__Rx>>
1503 public function f(): int;
1505 class A {
1506 <<__RxIfImplements(Rx::class)>>
1507 public function f(): int { ... }
1509 class B extends A {
1510 public function f(): int { ... }
1512 This should be OK because:
1513 - B does not implement Rx (B::f is not compatible with Rx::f) which means
1514 that calling ($b : B)->f() will not be treated as reactive
1515 - if one of subclasses of B will decide to implement B - they will be forced
1516 to redeclare f which now will shadow B::f. Note that B::f will still be
1517 accessible as parent::f() but will be treated as non-reactive call.
1519 | _, (Reactive (Some t) | Shallow (Some t) | Local (Some t)), Some { method_info = Some mi; _ }
1520 when condition_type_has_matching_reactive_method t mi ->
1521 true
1522 (* call_site specific cases *)
1523 (* shallow can call into local *)
1524 | Local cond_sub, Shallow cond_super, _ when
1525 is_call_site &&
1526 subtype_param_rx_if_impl ~is_param:false env cond_sub class_ty cond_super ->
1527 true
1528 (* local can call into non-reactive *)
1529 | Nonreactive, Local _, _ when is_call_site -> true
1530 | _ -> false
1532 and should_check_fun_params_reactivity
1533 (ft_super: locl fun_type) = ft_super.ft_reactive <> Nonreactive
1535 (* checks condition described by OnlyRxIfImpl condition on parameter is met *)
1536 and subtype_param_rx_if_impl
1537 ~is_param
1538 (env: Env.env)
1539 (cond_type_sub: decl ty option)
1540 (declared_type_sub: locl ty option)
1541 (cond_type_super: decl ty option) =
1542 let cond_type_sub =
1543 Option.map cond_type_sub ~f:(ConditionTypes.localize_condition_type env) in
1544 let cond_type_super =
1545 Option.map cond_type_super ~f:(ConditionTypes.localize_condition_type env) in
1546 match cond_type_sub, cond_type_super with
1547 (* no condition types - do nothing *)
1548 | None, None -> true
1549 (* condition type is specified only for super - ok for receiver case (is_param is false)
1550 abstract class A {
1551 <<__RxLocal, __OnlyRxIfImpl(Rx1::class)>>
1552 public abstract function condlocalrx(): int;
1554 abstract class B extends A {
1555 // ok to override cond local with local (if condition is not met - method
1556 // in base class is non-reactive )
1557 <<__Override, __RxLocal>>
1558 public function condlocalrx(): int {
1559 return 1;
1562 for parameters we need to verify that declared type of sub is a subtype of
1563 conditional type for super. Here is an example where this is violated:
1565 interface A {}
1566 interface RxA {}
1568 class C1 {
1569 <<__Rx>>
1570 public function f(A $a): void {
1574 class C2 extends C1 {
1575 // ERROR: invariant f body is reactive iff $a instanceof RxA can be violated
1576 <<__Rx, __AtMostRxAsArgs>>
1577 public function f(<<__OnlyRxIfImpl(RxA::class)>>A $a): void {
1580 here declared type of sub is A
1581 and cond type of super is RxA
1583 | None, Some _ when not is_param -> true
1584 | None, Some cond_type_super ->
1585 Option.value_map declared_type_sub
1586 ~default:false
1587 ~f:(fun declared_type_sub ->
1588 is_sub_type_LEGACY_DEPRECATED env declared_type_sub cond_type_super)
1589 (* condition types are set for both sub and super types: contravariant check
1590 interface A {}
1591 interface B extends A {}
1592 interface C extends B {}
1594 interface I1 {
1595 <<__Rx, __OnlyRxIfImpl(B::class)>>
1596 public function f(): void;
1597 <<__Rx>>
1598 public function g(<<__OnlyRxIfImpl(B::class)>> A $a): void;
1600 interface I2 extends I1 {
1601 // OK since condition in I1::f covers I2::f
1602 <<__Rx, __OnlyRxIfImpl(A::class)>>
1603 public function f(): void;
1604 // OK since condition in I1::g covers I2::g
1605 <<__Rx>>
1606 public function g(<<__OnlyRxIfImpl(A::class)>> A $a): void;
1608 interface I3 extends I1 {
1609 // Error since condition in I1::f is less strict that in I3::f
1610 <<__Rx, __OnlyRxIfImpl(C::class)>>
1611 public function f(): void;
1612 // Error since condition in I1::g is less strict that in I3::g
1613 <<__Rx>>
1614 public function g(<<__OnlyRxIfImpl(C::class)>> A $a): void;
1617 | Some cond_type_sub, Some cond_type_super ->
1618 is_sub_type_LEGACY_DEPRECATED env cond_type_super cond_type_sub
1619 (* condition type is set for super type, check if declared type of
1620 subtype is a subtype of condition type
1621 interface Rx {
1622 <<__Rx>>
1623 public function f(int $a): void;
1625 class A<T> {
1626 <<__Rx, __OnlyRxIfImpl(Rx::class)>>
1627 public function f(T $a): void {
1630 // B <: Rx so B::f is completely reactive
1631 class B extends A<int> implements Rx {
1632 } *)
1633 | Some cond_type_sub, None ->
1634 Option.value_map declared_type_sub
1635 ~default:false
1636 ~f:(fun declared_type_sub -> is_sub_type_LEGACY_DEPRECATED env declared_type_sub cond_type_sub)
1638 (* checks reactivity conditions for function parameters *)
1639 and subtype_fun_params_reactivity
1640 (p_sub: locl fun_param)
1641 (p_super: locl fun_param)
1642 env =
1643 match p_sub.fp_rx_annotation, p_super.fp_rx_annotation with
1644 (* no conditions on parameters - do nothing *)
1645 | None, None -> valid env
1646 (* both parameters are conditioned to be rx function - no need to check anything *)
1647 | Some Param_rx_var, Some Param_rx_var -> valid env
1648 | None, Some Param_rx_var ->
1649 (* parameter is conditionally reactive in supertype and missing condition
1650 in subtype - this is ok only if parameter in subtype is reactive
1651 <<__Rx>>
1652 function super((function(): int) $f);
1653 <<__Rx>>
1654 function sub(<<__AtMostRxAsFunc>> (function(): int) $f);
1655 We check if sub <: super. parameters are checked contravariantly
1656 so we need to verify that
1657 (function(): int) $f <: <<__AtMostRxAsFunc>> (function(): int) $f
1659 Suppose this is legal, then this will be allowed (in pseudo-code)
1661 function sub(<<__AtMostRxAsFunc>> (function(): int) $f) {
1662 $f(); // can call function here since it is conditionally reactive
1664 <<__Rx>>
1665 function g() {
1666 $f: super = sub;
1667 // invoke non-reactive code in reactive context which is bad
1668 $f(() ==> { echo 1; });
1671 It will be safe if parameter in super will be completely reactive,
1672 hence check below *)
1673 let _, p_sub_type = Env.expand_type env p_sub.fp_type in
1674 begin match p_sub_type with
1675 | _, Tfun tfun when tfun.ft_reactive <> Nonreactive -> valid env
1676 | _, Tfun _ ->
1677 env, TL.invalid ~fail:(fun () -> Errors.rx_parameter_condition_mismatch
1678 SN.UserAttributes.uaAtMostRxAsFunc p_sub.fp_pos p_super.fp_pos)
1679 (* parameter type is not function - error will be reported in different place *)
1680 | _ -> valid env
1682 | cond_sub, cond_super ->
1683 let cond_type_sub =
1684 match cond_sub with
1685 | Some (Param_rx_if_impl t) -> Some t
1686 | _ -> None in
1687 let cond_type_super =
1688 match cond_super with
1689 | Some (Param_rx_if_impl t) -> Some t
1690 | _ -> None in
1691 let ok =
1692 subtype_param_rx_if_impl ~is_param:true env cond_type_sub (Some p_sub.fp_type)
1693 cond_type_super in
1694 check_with ok (fun () ->
1695 Errors.rx_parameter_condition_mismatch
1696 SN.UserAttributes.uaOnlyRxIfImpl p_sub.fp_pos p_super.fp_pos) (env, TL.valid)
1698 (* Helper function for subtyping on function types: performs all checks that
1699 * don't involve actual types:
1700 * <<__ReturnDisposable>> attribute
1701 * <<__MutableReturn>> attribute
1702 * <<__Rx>> attribute
1703 * <<__Mutable>> attribute
1704 * whether or not the function is a coroutine
1705 * variadic arity
1707 and check_subtype_funs_attributes
1708 ?(extra_info: reactivity_extra_info option)
1709 (r_sub : Reason.t)
1710 (ft_sub : locl fun_type)
1711 (r_super : Reason.t)
1712 (ft_super : locl fun_type) env =
1713 let p_sub = Reason.to_pos r_sub in
1714 let p_super = Reason.to_pos r_super in
1715 (env, TL.valid) |>
1716 check_with
1717 (subtype_reactivity ?extra_info env ft_sub.ft_reactive ft_super.ft_reactive)
1718 (fun () -> Errors.fun_reactivity_mismatch
1719 p_super (TUtils.reactivity_to_string env ft_super.ft_reactive)
1720 p_sub (TUtils.reactivity_to_string env ft_sub.ft_reactive))
1722 check_with
1723 (ft_sub.ft_is_coroutine = ft_super.ft_is_coroutine)
1724 (fun () -> Errors.coroutinness_mismatch ft_super.ft_is_coroutine p_super p_sub) |>
1725 check_with
1726 (ft_sub.ft_return_disposable = ft_super.ft_return_disposable)
1727 (fun () -> Errors.return_disposable_mismatch ft_super.ft_return_disposable p_super p_sub) |>
1728 (* it is ok for subclass to return mutably owned value and treat it as immutable -
1729 the fact that value is mutably owned guarantees it has only single reference so
1730 as a result this single reference will be immutable. However if super type
1731 returns mutable value and subtype yields immutable value - this is not safe.
1732 NOTE: error is not reported if child is non-reactive since it does not have
1733 immutability-by-default behavior *)
1734 check_with
1735 (ft_sub.ft_returns_mutable = ft_super.ft_returns_mutable
1736 || not ft_super.ft_returns_mutable
1737 || ft_sub.ft_reactive = Nonreactive)
1738 (fun () -> Errors.mutable_return_result_mismatch ft_super.ft_returns_mutable p_super p_sub) |>
1739 check_with
1740 (ft_super.ft_reactive = Nonreactive
1741 || ft_super.ft_returns_void_to_rx
1742 || not ft_sub.ft_returns_void_to_rx)
1743 (fun () ->
1744 (* __ReturnsVoidToRx can be omitted on subtype, in this case using subtype
1745 via reference to supertype in rx context will be ok since result will be
1746 discarded. The opposite is not true:
1747 class A {
1748 <<__Rx, __Mutable>>
1749 public function f(): A { return new A(); }
1751 class B extends A {
1752 <<__Rx, __Mutable, __ReturnsVoidToRx>>
1753 public function f(): A { return $this; }
1756 <<__Rx, __MutableReturn>>
1757 function f(): A { return new B(); }
1758 $a = HH\Rx\mutable(f());
1759 $a1 = $a->f(); // immutable alias to mutable reference *)
1760 Errors.return_void_to_rx_mismatch ~pos1_has_attribute:true p_sub p_super) |>
1761 (* check mutability only for reactive functions *)
1762 let check_params_mutability =
1763 ft_super.ft_reactive <> Nonreactive &&
1764 ft_sub.ft_reactive <> Nonreactive in
1765 fun (env, prop) -> (if check_params_mutability
1766 (* check mutability of receivers *)
1767 then (env, prop) &&&
1768 check_mutability ~is_receiver:true
1769 p_super ft_super.ft_mutability p_sub ft_sub.ft_mutability else env, prop) |>
1770 check_with
1771 ((arity_min ft_sub.ft_arity) <= (arity_min ft_super.ft_arity))
1772 (fun () -> Errors.fun_too_many_args p_sub p_super)
1774 fun res -> (match ft_sub.ft_arity, ft_super.ft_arity with
1775 | Fellipsis _, Fvariadic _ ->
1776 (* The HHVM runtime ignores "..." entirely, but knows about
1777 * "...$args"; for contexts for which the runtime enforces method
1778 * compatibility (currently, inheritance from abstract/interface
1779 * methods), letting "..." override "...$args" would result in method
1780 * compatibility errors at runtime. *)
1781 with_error (fun () -> Errors.fun_variadicity_hh_vs_php56 p_sub p_super) res
1782 | Fstandard (_, sub_max), Fstandard (_, super_max) ->
1783 if sub_max < super_max
1784 then with_error (fun () -> Errors.fun_too_few_args p_sub p_super) res else res
1785 | Fstandard _, _ -> with_error (fun () -> Errors.fun_unexpected_nonvariadic p_sub p_super) res
1786 | _, _ -> res
1789 (* This implements basic subtyping on non-generic function types:
1790 * (1) return type behaves covariantly
1791 * (2) parameter types behave contravariantly
1792 * (3) special casing for variadics, and various reactivity and mutability attributes
1794 and simplify_subtype_funs
1795 ~(seen_generic_params : SSet.t option)
1796 ~(no_top_bottom : bool)
1797 ~(check_return : bool)
1798 ?(extra_info: reactivity_extra_info option)
1799 (r_sub : Reason.t)
1800 (ft_sub : locl fun_type)
1801 (r_super : Reason.t)
1802 (ft_super : locl fun_type)
1803 (on_error : Errors.typing_error_callback)
1805 : Env.env * TL.subtype_prop =
1806 let variadic_subtype = match ft_sub.ft_arity with
1807 | Fvariadic (_, {fp_type = var_sub; _ }) -> Some var_sub
1808 | _ -> None in
1809 let variadic_supertype = match ft_super.ft_arity with
1810 | Fvariadic (_, {fp_type = var_super; _ }) -> Some var_super
1811 | _ -> None in
1813 let simplify_subtype = simplify_subtype ~seen_generic_params ~no_top_bottom ~on_error in
1814 let simplify_subtype_params = simplify_subtype_params ~seen_generic_params
1815 ~no_top_bottom ~on_error in
1817 (* First apply checks on attributes, coroutine-ness and variadic arity *)
1818 env |>
1819 check_subtype_funs_attributes ?extra_info r_sub ft_sub r_super ft_super &&&
1821 (* Now do contravariant subtyping on parameters *)
1822 begin
1823 match variadic_subtype, variadic_supertype with
1824 | Some var_sub, Some var_super -> simplify_subtype var_super var_sub
1825 | _ -> valid
1826 end &&&
1828 begin
1829 let check_params_mutability =
1830 ft_super.ft_reactive <> Nonreactive &&
1831 ft_sub.ft_reactive <> Nonreactive in
1832 let is_method =
1833 (Option.map extra_info (fun i -> Option.is_some i.method_info)) = Some true in
1834 simplify_subtype_params
1835 ~is_method
1836 ~check_params_reactivity:(should_check_fun_params_reactivity ft_super)
1837 ~check_params_mutability
1838 ft_super.ft_params ft_sub.ft_params variadic_subtype variadic_supertype
1839 end &&&
1841 (* Finally do covariant subtryping on return type *)
1842 if check_return
1843 then simplify_subtype ft_sub.ft_ret ft_super.ft_ret
1844 else valid
1846 (* One of the main entry points to this module *)
1847 and sub_type
1848 (env : Env.env)
1849 (ty_sub : locl ty)
1850 (ty_super : locl ty)
1851 (on_error : Errors.typing_error_callback)
1852 : Env.env =
1853 Env.log_env_change "sub_type" env @@
1854 sub_type_inner env ~this_ty:None ty_sub ty_super on_error
1856 (* Add a new upper bound ty on var. Apply transitivity of sutyping,
1857 * so if we already have tyl <: var, then check that for each ty_sub
1858 * in tyl we have ty_sub <: ty.
1860 and add_tyvar_upper_bound_and_close env var ty on_error =
1861 Env.log_env_change "add_tyvar_upper_bound_and_close" env @@
1862 let upper_bounds_before = Env.get_tyvar_upper_bounds env var in
1863 let env = Env.add_tyvar_upper_bound ~intersect:(try_intersect env) env var ty in
1864 let upper_bounds_after = Env.get_tyvar_upper_bounds env var in
1865 let added_upper_bounds = Typing_set.diff upper_bounds_after upper_bounds_before in
1866 let lower_bounds = Env.get_tyvar_lower_bounds env var in
1867 let env =
1868 Typing_set.fold (fun upper_bound env ->
1869 let env = Typing_subtype_tconst.make_all_type_consts_equal env var
1870 upper_bound ~as_tyvar_with_cnstr:true in
1871 Typing_set.fold (fun lower_bound env ->
1872 sub_type env lower_bound upper_bound on_error)
1873 lower_bounds env)
1874 added_upper_bounds env in
1877 (* Add a new lower bound ty on var. Apply transitivity of sutyping,
1878 * so if we already have var <: tyl, then check that for each ty_super
1879 * in tyl we have ty <: ty_super.
1881 and add_tyvar_lower_bound_and_close env var ty on_error =
1882 Env.log_env_change "add_tyvar_lower_bound_and_close" env @@
1883 let lower_bounds_before = Env.get_tyvar_lower_bounds env var in
1884 let env = Env.add_tyvar_lower_bound ~union:(try_union env) env var ty in
1885 let lower_bounds_after = Env.get_tyvar_lower_bounds env var in
1886 let added_lower_bounds = Typing_set.diff lower_bounds_after lower_bounds_before in
1887 let upper_bounds = Env.get_tyvar_upper_bounds env var in
1888 let env =
1889 Typing_set.fold (fun lower_bound env ->
1890 let env = Typing_subtype_tconst.make_all_type_consts_equal env var
1891 lower_bound ~as_tyvar_with_cnstr:false in
1892 Typing_set.fold (fun upper_bound env ->
1893 sub_type env lower_bound upper_bound on_error)
1894 upper_bounds env)
1895 added_lower_bounds env in
1898 and props_to_env env remain props on_error =
1899 match props with
1900 | [] ->
1901 env, List.rev remain
1902 | TL.IsSubtype (((_, Tvar var_sub) as ty_sub), ((_, Tvar var_super) as ty_super)) :: props ->
1903 let env = add_tyvar_upper_bound_and_close env var_sub ty_super on_error in
1904 let env = add_tyvar_lower_bound_and_close env var_super ty_sub on_error in
1905 props_to_env env remain props on_error
1906 | TL.IsSubtype ((_, Tvar var), ty) :: props ->
1907 let env = add_tyvar_upper_bound_and_close env var ty on_error in
1908 props_to_env env remain props on_error
1909 | TL.IsSubtype (ty, (_, Tvar var)) :: props ->
1910 let env = add_tyvar_lower_bound_and_close env var ty on_error in
1911 props_to_env env remain props on_error
1912 | TL.Conj props' :: props ->
1913 props_to_env env remain (props' @ props) on_error
1914 | TL.Disj (f, disj_props) :: conj_props ->
1915 (* For now, just find the first prop in the disjunction that works *)
1916 let rec try_disj disj_props =
1917 match disj_props with
1918 | [] ->
1919 (* For now let it fail later when calling
1920 process_simplify_subtype_result on the remaining constraints. *)
1921 props_to_env env (TL.invalid ~fail:f :: remain) conj_props on_error
1922 | prop :: disj_props' ->
1923 Errors.try_
1924 (fun () ->
1925 ignore_hh_fixmes (fun () -> props_to_env env remain (prop::conj_props) on_error))
1926 (fun _ -> try_disj disj_props')
1928 try_disj disj_props
1929 | prop :: props ->
1930 props_to_env env (prop::remain) props on_error
1932 (* Move any top-level conjuncts of the form Tvar v <: t or t <: Tvar v to
1933 * the type variable environment. To do: use intersection and union to
1934 * simplify bounds.
1936 and prop_to_env env prop on_error =
1937 let env, props' = props_to_env env [] [prop] on_error in
1938 env, TL.conj_list props'
1940 and env_to_prop env =
1941 TL.conj (tvenv_to_prop env.Env.tvenv) env.Env.subtype_prop
1943 and tvenv_to_prop tvenv =
1944 let props_per_tvar = IMap.mapi (
1945 fun id { Env.lower_bounds; Env.upper_bounds; _ } ->
1946 let tyvar = (Reason.Rnone, Tvar id) in
1947 let lower_bounds = TySet.elements lower_bounds in
1948 let upper_bounds = TySet.elements upper_bounds in
1949 let lower_bounds_props = List.map ~f:(fun ty -> TL.IsSubtype (ty, tyvar))
1950 lower_bounds in
1951 (* If an upper bound of variable n1 is a `Tvar n2`,
1952 then we have already added "Tvar n1 <: Tvar n2" when traversing
1953 lower bounds of n2, so we can filter out upper bounds that are Tvars. *)
1954 let can_be_removed = function
1955 | _, Tvar n ->
1956 begin match IMap.find_opt n tvenv with
1957 | Some _ -> true
1958 | None -> false
1960 | _ -> false in
1961 let upper_bounds = List.filter ~f:(fun ty -> not (can_be_removed ty))
1962 upper_bounds in
1963 let upper_bounds_props = List.map ~f:(fun ty -> TL.IsSubtype (tyvar, ty))
1964 upper_bounds in
1965 TL.conj_list (lower_bounds_props @ upper_bounds_props))
1966 tvenv in
1967 let _ids, props = List.unzip (IMap.bindings props_per_tvar) in
1968 TL.conj_list props
1970 and sub_type_inner
1971 (env : Env.env)
1972 ~(this_ty : locl ty option)
1973 (ty_sub: locl ty)
1974 (ty_super: locl ty)
1975 (on_error : Errors.typing_error_callback)
1976 : Env.env =
1977 log_subtype ~level:1 ~this_ty ~function_name:"sub_type_inner" env ty_sub ty_super;
1978 let env, prop = simplify_subtype
1979 ~seen_generic_params:empty_seen
1980 ~no_top_bottom:false
1981 ~this_ty ty_sub ty_super ~on_error env in
1982 let env, prop = prop_to_env env prop on_error in
1983 let env = Env.add_subtype_prop env prop in
1984 process_simplify_subtype_result prop;
1987 (* BEWARE: hack upon hack here.
1988 * To implement a predicate that tests whether `ty_sub` is a subtype of
1989 * `ty_super`, we call sub_type but handle any unification errors and
1990 * turn them into `false` result. Unfortunately HH_FIXME might end up
1991 * hiding the "error", and so we need to disable the fixme mechanism
1992 * before calling sub_type and then re-enable it afterwards.
1994 and is_sub_type_LEGACY_DEPRECATED
1995 (env : Env.env)
1996 (ty_sub : locl ty)
1997 (ty_super : locl ty) : bool =
1998 (* quick short circuit to help perf *)
1999 ty_equal ty_sub ty_super ||
2000 Errors.try_
2001 (fun () ->
2002 ignore_hh_fixmes (fun () ->
2003 ignore (sub_type env ty_sub ty_super Errors.unify_error); true))
2004 (fun _ -> false)
2006 and is_sub_type_alt ~ignore_generic_params ~no_top_bottom env ty1 ty2 =
2007 let _env, prop = simplify_subtype
2008 ~seen_generic_params:(if ignore_generic_params then None else empty_seen)
2009 ~no_top_bottom
2010 ~this_ty:(Some ty1)
2011 (* It is weird that this can cause errors, but I am wary to discard them.
2012 * Using the generic unify_error to maintain current behavior. *)
2013 ty1 ty2 ~on_error:Errors.unify_error env in
2014 if TL.is_valid prop then Some true
2015 else
2016 if TL.is_unsat prop then Some false
2017 else None
2019 and is_sub_type env ty1 ty2 =
2020 is_sub_type_alt ~ignore_generic_params:false ~no_top_bottom:false env ty1 ty2 = Some true
2022 and is_sub_type_for_union env ty1 ty2 =
2023 is_sub_type_alt ~ignore_generic_params:false ~no_top_bottom:true env ty1 ty2 = Some true
2025 and can_sub_type env ty1 ty2 =
2026 is_sub_type_alt ~ignore_generic_params:false ~no_top_bottom:true env ty1 ty2 <> Some false
2028 and is_sub_type_ignore_generic_params env ty1 ty2 =
2029 is_sub_type_alt ~ignore_generic_params:true ~no_top_bottom:true env ty1 ty2 = Some true
2031 (* Attempt to compute the intersection of a type with an existing list intersection.
2032 * If try_intersect env t [t1;...;tn] = [u1; ...; um]
2033 * then u1&...&um must be the greatest lower bound of t and t1&...&tn wrt subtyping.
2034 * For example:
2035 * try_intersect nonnull [?C] = [C]
2036 * try_intersect t1 [t2] = [t1] if t1 <: t2
2037 * Note: it's acceptable to return [t;t1;...;tn] but the intention is that
2038 * we simplify (as above) wherever practical.
2039 * It can be assumed that the original list contains no redundancy.
2041 and try_intersect env ty tyl =
2042 match tyl with
2043 | [] -> [ty]
2044 | ty'::tyl' ->
2045 if is_sub_type_ignore_generic_params env ty ty'
2046 then try_intersect env ty tyl'
2047 else
2048 if is_sub_type_ignore_generic_params env ty' ty
2049 then tyl
2050 else
2051 let nonnull_ty = (fst ty, Tnonnull) in
2052 match ty, ty' with
2053 | (_, Toption t), _ when is_sub_type_ignore_generic_params env ty' nonnull_ty ->
2054 try_intersect env t (ty'::tyl')
2055 | _, (_, Toption t) when is_sub_type_ignore_generic_params env ty nonnull_ty ->
2056 try_intersect env t (ty::tyl')
2057 | _, _ -> ty' :: try_intersect env ty tyl'
2059 (* Attempt to compute the union of a type with an existing list union.
2060 * If try_union env t [t1;...;tn] = [u1;...;um]
2061 * then u1|...|um must be the least upper bound of t and t1|...|tn wrt subtyping.
2062 * For example:
2063 * try_union int [float] = [num]
2064 * try_union t1 [t2] = [t1] if t2 <: t1
2066 * Notes:
2067 * 1. It's acceptable to return [t;t1;...;tn] but the intention is that
2068 * we simplify (as above) wherever practical.
2069 * 2. Do not use Tunion for a syntactic union - the caller can do that.
2070 * 3. It can be assumed that the original list contains no redundancy.
2071 * TODO: there are many more unions to implement yet.
2073 and try_union env ty tyl =
2074 match tyl with
2075 | [] -> [ty]
2076 | ty'::tyl' ->
2077 if is_sub_type_for_union env ty ty'
2078 then tyl
2079 else
2080 if is_sub_type_for_union env ty' ty
2081 then try_union env ty tyl'
2082 else match snd ty, snd ty' with
2083 | Tprim Nast.Tfloat, Tprim Nast.Tint
2084 | Tprim Nast.Tint, Tprim Nast.Tfloat ->
2085 let t = MakeType.num (fst ty) in
2086 try_union env t tyl'
2087 | _, _ -> ty' :: try_union env ty tyl'
2089 (** Check that the method with signature ft_sub can be used to override
2090 * (is a subtype of) method with signature ft_super.
2092 * This goes beyond subtyping on function types because methods can have
2093 * generic parameters with bounds, and `where` constraints.
2095 * Suppose ft_super is of the form
2096 * <T1 csuper1, ..., Tn csupern>(tsuper1, ..., tsuperm) : tsuper where wsuper
2097 * and ft_sub is of the form
2098 * <T1 csub1, ..., Tn csubn>(tsub1, ..., tsubm) : tsub where wsub
2099 * where csuperX and csubX are constraints on type parameters and wsuper and
2100 * wsub are 'where' constraints. Note that all types in the superclass,
2101 * including constraints (so csuperX, tsuperX, tsuper and wsuper) have had
2102 * any class type parameters instantiated appropriately according to
2103 * the actual arguments of the superclass. For example, suppose we have
2105 * class Super<T> {
2106 * function foo<Tu as A<T>>(T $x) : B<T> where T super C<T>
2108 * class Sub extends Super<D> {
2109 * ...override of foo...
2111 * then the actual signature in the superclass that we need to check is
2112 * function foo<Tu as A<D>>(D $x) : B<D> where D super C<D>
2113 * Note in particular the general form of the 'where' constraint.
2115 * (Currently, this instantiation happens in
2116 * Typing_extends.check_class_implements which in turn calls
2117 * Decl_instantiate.instantiate_ce)
2119 * Then for ft_sub to be a subtype of ft_super it must be the case that
2120 * (1) tsuper1 <: tsub1, ..., tsupern <: tsubn (under constraints
2121 * T1 csuper1, ..., Tn csupern and wsuper).
2123 * This is contravariant subtyping on parameter types.
2125 * (2) tsub <: tsuper (under constraints T1 csuper1, ..., Tn csupern and wsuper)
2126 * This is covariant subtyping on result type. For constraints consider
2127 * e.g. consider ft_super = <T super I>(): T
2128 * and ft_sub = <T>(): I
2130 * (3) The constraints for ft_super entail the constraints for ft_sub, because
2131 * we might be calling the function having checked that csuperX are
2132 * satisfied but the definition of the function (e.g. consider an override)
2133 * has been checked under csubX.
2134 * More precisely, we must assume constraints T1 csuper1, ..., Tn csupern
2135 * and wsuper, and check that T1 satisfies csub1, ..., Tn satisfies csubn
2136 * and that wsub holds under those assumptions.
2138 let subtype_method
2139 ~(check_return : bool)
2140 ~(extra_info: reactivity_extra_info)
2141 (env : Env.env)
2142 (r_sub : Reason.t)
2143 (ft_sub : decl fun_type)
2144 (r_super : Reason.t)
2145 (ft_super : decl fun_type)
2146 (on_error : Errors.typing_error_callback) : Env.env =
2147 if not ft_super.ft_abstract && ft_sub.ft_abstract then
2148 (* It is valid for abstract class to extend a concrete class, but it cannot
2149 * redefine already concrete members as abstract.
2150 * See override_abstract_concrete.php test case for example. *)
2151 Errors.abstract_concrete_override ft_sub.ft_pos ft_super.ft_pos `method_;
2152 let ety_env =
2153 Phase.env_with_self env in
2154 let env, ft_super_no_tvars = Phase.localize_ft ~ety_env env ft_super in
2155 let env, ft_sub_no_tvars = Phase.localize_ft ~ety_env env ft_sub in
2156 let old_tpenv = Env.get_tpenv env in
2158 (* We check constraint entailment and contravariant parameter/covariant result
2159 * subtyping in the context of the ft_super constraints. But we'd better
2160 * restore tpenv afterwards *)
2161 let add_tparams_constraints env (tparams: locl tparam list) =
2162 let add_bound env { tp_name = (pos, name); tp_constraints = cstrl; _ } =
2163 List.fold_left cstrl ~init:env ~f:(fun env (ck, ty) ->
2164 let tparam_ty = (Reason.Rwitness pos,
2165 Tabstract(AKgeneric name, None)) in
2166 Typing_utils.add_constraint pos env ck tparam_ty ty) in
2167 List.fold_left tparams ~f:add_bound ~init: env in
2169 let p_sub = Reason.to_pos r_sub in
2171 let add_where_constraints env (cstrl: locl where_constraint list) =
2172 List.fold_left cstrl ~init:env ~f:(fun env (ty1, ck, ty2) ->
2173 Typing_utils.add_constraint p_sub env ck ty1 ty2) in
2175 let env =
2176 add_tparams_constraints env (fst ft_super_no_tvars.ft_tparams) in
2177 let env =
2178 add_where_constraints env ft_super_no_tvars.ft_where_constraints in
2180 let env, res =
2181 simplify_subtype_funs
2182 ~seen_generic_params:empty_seen
2183 ~no_top_bottom:false
2184 ~check_return
2185 ~extra_info
2186 r_sub ft_sub_no_tvars
2187 r_super ft_super_no_tvars
2188 on_error
2189 env in
2191 process_simplify_subtype_result res;
2193 (* This is (3) above *)
2194 let check_tparams_constraints env tparams =
2195 let check_tparam_constraints env { tp_name = (p, name); tp_constraints = cstrl; _ } =
2196 List.fold_left cstrl ~init:env ~f:begin fun env (ck, cstr_ty) ->
2197 let tgeneric = (Reason.Rwitness p, Tabstract (AKgeneric name, None)) in
2198 Typing_generic_constraint.check_constraint env ck tgeneric ~cstr_ty
2199 end in
2200 List.fold_left tparams ~init:env ~f:check_tparam_constraints in
2202 let check_where_constraints env cstrl =
2203 List.fold_left cstrl ~init:env ~f:begin fun env (ty1, ck, ty2) ->
2204 Typing_generic_constraint.check_constraint env ck ty1 ~cstr_ty:ty2
2205 end in
2207 (* We only do this if the ft_tparam lengths match. Currently we don't even
2208 * report this as an error, indeed different names for type parameters.
2209 * TODO: make it an error to override with wrong number of type parameters
2211 let env =
2212 if List.length (fst ft_sub.ft_tparams) <> List.length (fst ft_super.ft_tparams)
2213 then env
2214 else check_tparams_constraints env (fst ft_sub_no_tvars.ft_tparams) in
2215 let env =
2216 check_where_constraints env ft_sub_no_tvars.ft_where_constraints in
2218 Env.env_with_tpenv env old_tpenv
2220 let decompose_subtype_add_bound
2221 (env : Env.env)
2222 (ty_sub : locl ty)
2223 (ty_super : locl ty)
2224 : Env.env =
2225 let env, ty_super = Env.expand_type env ty_super in
2226 let env, ty_sub = Env.expand_type env ty_sub in
2227 match ty_sub, ty_super with
2228 | _, (_, Tany) ->
2231 (* name_sub <: ty_super so add an upper bound on name_sub *)
2232 | (_, Tabstract (AKgeneric name_sub, _)), _ when not (phys_equal ty_sub ty_super) ->
2233 log_subtype ~level:2 ~this_ty:None ~function_name:"decompose_subtype_add_bound" env ty_sub ty_super;
2234 let tys = Env.get_upper_bounds env name_sub in
2235 (* Don't add the same type twice! *)
2236 if Typing_set.mem ty_super tys then env
2237 else Env.add_upper_bound ~intersect:(try_intersect env) env name_sub ty_super
2239 (* ty_sub <: name_super so add a lower bound on name_super *)
2240 | _, (_, Tabstract (AKgeneric name_super, _)) when not (phys_equal ty_sub ty_super) ->
2241 log_subtype ~level:2 ~this_ty:None ~function_name:"decompose_subtype_add_bound" env ty_sub ty_super;
2242 let tys = Env.get_lower_bounds env name_super in
2243 (* Don't add the same type twice! *)
2244 if Typing_set.mem ty_sub tys then env
2245 else Env.add_lower_bound ~union:(try_union env) env name_super ty_sub
2247 | _, _ ->
2250 (* Given two types that we know are in a subtype relationship
2251 * ty_sub <: ty_super
2252 * add to env.tpenv any bounds on generic type parameters that must
2253 * hold for ty_sub <: ty_super to be valid.
2255 * For example, suppose we know Cov<T> <: Cov<D> for a covariant class Cov.
2256 * Then it must be the case that T <: D so we add an upper bound D to the
2257 * bounds for T.
2259 * Although some of this code is similar to that for sub_type_inner, its
2260 * purpose is different. sub_type_inner takes two types t and u and makes
2261 * updates to the substitution of type variables (through unification) to
2262 * make t <: u true.
2264 * decompose_subtype takes two types t and u for which t <: u is *assumed* to
2265 * hold, and makes updates to bounds on generic parameters that *necessarily*
2266 * hold in order for t <: u.
2268 let rec decompose_subtype
2270 (env : Env.env)
2271 (ty_sub : locl ty)
2272 (ty_super : locl ty)
2273 (on_error : Errors.typing_error_callback)
2274 : Env.env =
2275 log_subtype ~level:2 ~this_ty:None ~function_name:"decompose_subtype" env ty_sub ty_super;
2276 let env, prop =
2277 simplify_subtype ~seen_generic_params:None
2278 ~no_top_bottom:false ~this_ty:None ty_sub ty_super ~on_error env in
2279 decompose_subtype_add_prop p env prop
2281 and decompose_subtype_add_prop p env prop =
2282 match prop with
2283 | TL.Conj props ->
2284 List.fold_left ~f:(decompose_subtype_add_prop p) ~init:env props
2285 | TL.Disj (_, [prop']) ->
2286 decompose_subtype_add_prop p env prop'
2287 | TL.Disj _ ->
2288 Typing_log.log_prop 2 env.Env.function_pos "decompose_subtype_add_prop" env prop;
2290 | TL.IsSubtype (ty1, ty2) ->
2291 decompose_subtype_add_bound env ty1 ty2
2293 (* Decompose a general constraint *)
2294 and decompose_constraint
2296 (env : Env.env)
2297 (ck : Ast_defs.constraint_kind)
2298 (ty_sub : locl ty)
2299 (ty_super : locl ty)
2300 : Env.env =
2301 (* constraints are caught based on reason, not error callback. Using unify_error *)
2302 match ck with
2303 | Ast_defs.Constraint_as ->
2304 decompose_subtype p env ty_sub ty_super Errors.unify_error
2305 | Ast_defs.Constraint_super ->
2306 decompose_subtype p env ty_super ty_sub Errors.unify_error
2307 | Ast_defs.Constraint_eq ->
2308 let env' = decompose_subtype p env ty_sub ty_super Errors.unify_error in
2309 decompose_subtype p env' ty_super ty_sub Errors.unify_error
2310 | Ast_defs.Constraint_pu_from -> failwith "TODO(T36532263): Pocket Universes"
2312 (* Given a constraint ty1 ck ty2 where ck is AS, SUPER or =,
2313 * add bounds to type parameters in the environment that necessarily
2314 * must hold in order for ty1 ck ty2.
2316 * First, we invoke decompose_constraint to add initial bounds to
2317 * the environment. Then we iterate, decomposing constraints that
2318 * arise through transitivity across bounds.
2320 * For example, suppose that env already contains
2321 * C<T1> <: T2
2322 * for some covariant class C. Now suppose we add the
2323 * constraint "T2 as C<T3>" i.e. we end up with
2324 * C<T1> <: T2 <: C<T3>
2325 * Then by transitivity we know that T1 <: T3 so we add this to the
2326 * environment too.
2328 * We repeat this process until no further bounds are added to the
2329 * environment, or some limit is reached. (It's possible to construct
2330 * types that expand forever under inheritance.)
2332 let constraint_iteration_limit = 20
2333 let add_constraint
2335 (env : Env.env)
2336 (ck : Ast_defs.constraint_kind)
2337 (ty_sub : locl ty)
2338 (ty_super : locl ty) : Env.env =
2339 log_subtype ~level:1 ~this_ty:None ~function_name:"add_constraint" env ty_sub ty_super;
2340 let oldsize = Env.get_tpenv_size env in
2341 let env' = decompose_constraint p env ck ty_sub ty_super in
2342 if Env.get_tpenv_size env' = oldsize
2343 then env'
2344 else
2345 let rec iter n env =
2346 if n > constraint_iteration_limit then env
2347 else
2348 let oldsize = Env.get_tpenv_size env in
2349 let env' =
2350 List.fold_left (Env.get_generic_parameters env) ~init:env
2351 ~f:(fun env x ->
2352 List.fold_left (Typing_set.elements (Env.get_lower_bounds env x)) ~init:env
2353 ~f:(fun env ty_sub' ->
2354 List.fold_left (Typing_set.elements (Env.get_upper_bounds env x)) ~init:env
2355 ~f:(fun env ty_super' ->
2356 decompose_subtype p env ty_sub' ty_super' Errors.unify_error))) in
2357 if Env.get_tpenv_size env' = oldsize
2358 then env'
2359 else iter (n+1) env'
2361 iter 0 env'
2363 let log_prop env =
2364 let filename = Pos.filename (Pos.to_absolute env.Env.function_pos) in
2365 if Str.string_match (Str.regexp {|.*\.hhi|}) filename 0 then () else
2366 let prop = env_to_prop env in
2367 if TypecheckerOptions.log_inference_constraints (Env.get_tcopt env) then (
2368 let p_as_string = Typing_print.subtype_prop env prop in
2369 let pos = Pos.string (Pos.to_absolute env.Env.function_pos) in
2370 let size = TL.size prop in
2371 let n_disj = TL.n_disj prop in
2372 let n_conj = TL.n_conj prop in
2373 TypingLogger.InferenceCnstr.log p_as_string ~pos ~size ~n_disj ~n_conj);
2374 if not (Errors.currently_has_errors ()) &&
2375 not (TL.is_valid prop)
2376 then Typing_log.log_prop 1 env.Env.function_pos
2377 "There are remaining unsolved constraints!" env prop
2379 (*****************************************************************************)
2380 (* Exporting *)
2381 (*****************************************************************************)
2383 let () = Typing_utils.sub_type_ref := sub_type
2384 let () = Typing_utils.add_constraint_ref := add_constraint
2385 let () = Typing_utils.is_sub_type_for_union_ref := is_sub_type_for_union