New inference: flatten unions when solving for lower bounds
[hiphop-php.git] / hphp / hack / src / typing / typing_subtype.ml
blob2812eb4698bf3ab25715a838a58d525163907bf3
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 Subst = Decl_subst
19 module TUtils = Typing_utils
20 module SN = Naming_special_names
21 module Phase = Typing_phase
22 module TL = Typing_logic
23 module Cls = Typing_classes_heap
24 module TySet = Typing_set
25 module MakeType = Typing_make_type
27 type reactivity_extra_info = {
28 method_info: ((* method_name *) string * (* is_static *) bool) option;
29 class_ty: phase_ty option;
30 parent_class_ty: phase_ty option
33 let empty_extra_info = {
34 method_info = None;
35 class_ty = None;
36 parent_class_ty = None
39 module ConditionTypes = struct
40 let try_get_class_for_condition_type (env: Env.env) (ty: decl ty) =
41 match TUtils.try_unwrap_class_type ty with
42 | None -> None
43 | Some (_, ((_, x) as sid), _) ->
44 begin match Env.get_class env x with
45 | None -> None
46 | Some cls -> Some (sid, cls)
47 end
49 let try_get_method_from_condition_type
50 (env: Env.env)
51 (ty: decl ty)
52 (is_static: bool)
53 (method_name: string) =
54 match try_get_class_for_condition_type env ty with
55 | Some (_, cls) ->
56 let get = if is_static then Cls.get_smethod else Cls.get_method in
57 get cls method_name
58 | None -> None
61 let localize_condition_type (env: Env.env) (ty: decl ty): locl ty =
62 (* if condition type is generic - we cannot specify type argument in attribute.
63 For cases when we check if containing type is a subtype of condition type
64 if condition type is generic instantiate it with TAny's *)
65 let ty =
66 match try_get_class_for_condition_type env ty with
67 | None -> ty
68 | Some (_, cls) when Cls.tparams cls = [] -> ty
69 | Some (((p, _) as sid), cls) ->
70 let params =
71 List.map (Cls.tparams cls)
72 ~f:(fun { tp_name = (p,x); _ } -> Reason.Rwitness p, Tgeneric x) in
73 let subst =
74 Decl_instantiate.make_subst (Cls.tparams cls) [] in
75 let ty = Reason.Rwitness p, (Tapply (sid, params)) in
76 Decl_instantiate.instantiate subst ty in
77 let ety_env = Phase.env_with_self env in
78 let _, t = Phase.localize ~ety_env env ty in
80 end
82 (* Given a pair of types `ty_sub` and `ty_super` attempt to apply simplifications
83 * and add to the accumulated constraints in `constraints` any necessary and
84 * sufficient [(t1,ck1,u1);...;(tn,ckn,un)] such that
85 * ty_sub <: ty_super iff t1 ck1 u1, ..., tn ckn un
86 * where ck is `as` or `=`. Essentially we are making solution-preserving
87 * simplifications to the subtype assertion, for now, also generating equalities
88 * as well as subtype assertions, for backwards compatibility with use of
89 * unification.
91 * If `constraints = []` is returned then the subtype assertion is valid.
93 * If the subtype assertion is unsatisfiable then return `failed = Some f`
94 * where `f` is a `unit-> unit` function that records an error message.
95 * (Sometimes we don't want to call this function e.g. when just checking if
96 * a subtype holds)
98 * If deep=true, elide singleton unions, treat invariant generics as both-ways
99 * subtypes, and actually chase hierarchy for extends and implements.
100 * For now, deep=false is used by subtype solving (conservative) and
101 * deep=true is used for constraint decomposition (for instanceof).
103 * Annoyingly, we need to pass env back too, because Typing_phase.localize
104 * expands type constants. (TODO: work out a better way of handling this)
106 * Special cases:
107 * If assertion is valid (e.g. string <: arraykey) then
108 * result can be the empty list (i.e. nothing is added to the result)
109 * If assertion is unsatisfiable (e.g. arraykey <: string) then
110 * we record this in the failed field of the result.
112 let with_error (f : unit -> unit) ((env, p) : (Env.env * TL.subtype_prop))
113 : Env.env * TL.subtype_prop =
114 env, TL.conj p (TL.Unsat f)
116 (* If `b` is false then fail with error function `f` *)
117 let check_with b f r = if not b then with_error f r else r
119 let valid env : Env.env * TL.subtype_prop = env, TL.valid
121 let (&&&) (env, p1) (f : Env.env -> Env.env * TL.subtype_prop) =
122 if TL.is_unsat p1
123 then env, p1
124 else
125 let env, p2 = f env in
126 env, TL.conj p1 p2
128 let (|||) (env, p1) (f : Env.env -> Env.env * TL.subtype_prop) =
129 if TL.is_valid p1
130 then env, p1
131 else
132 let env, p2 = f env in
133 env, TL.disj p1 p2
135 let if_unsat (f : unit -> Env.env * TL.subtype_prop) (env, p) =
136 if TL.is_unsat p
137 then f ()
138 else env, p
140 (** Check that a mutability type is a subtype of another mutability type *)
141 let check_mutability
142 ~(is_receiver: bool)
143 (p_sub : Pos.t)
144 (mut_sub: param_mutability option)
145 (p_super : Pos.t)
146 (mut_super: param_mutability option)
147 env =
148 let str m =
149 match m with
150 | None -> "immutable"
151 | Some Param_owned_mutable -> "owned mutable"
152 | Some Param_borrowed_mutable -> "mutable"
153 | Some Param_maybe_mutable -> "maybe-mutable" in
154 (* maybe-mutable <------immutable
156 <--mutable <-- owned mutable *)
157 match mut_sub, mut_super with
158 (* immutable is not compatible with mutable *)
159 | None, Some (Param_borrowed_mutable | Param_owned_mutable)
160 (* mutable is not compatible with immutable *)
161 | Some (Param_borrowed_mutable | Param_owned_mutable), None
162 (* borrowed mutable is not compatible with owned mutable *)
163 | Some Param_borrowed_mutable, Some Param_owned_mutable
164 (* maybe-mutable is not compatible with immutable/mutable *)
165 | Some Param_maybe_mutable, (None | Some (Param_borrowed_mutable | Param_owned_mutable))
167 env, TL.Unsat (fun () -> Errors.mutability_mismatch
168 ~is_receiver p_sub (str mut_sub) p_super (str mut_super))
169 | _ ->
170 valid env
172 let empty_seen = Some SSet.empty
174 let log_subtype ~this_ty function_name env ty_sub ty_super =
175 Typing_log.(log_with_level env "sub" 2 begin fun () ->
176 let types =
177 [Log_type ("ty_sub", ty_sub);
178 Log_type ("ty_super", ty_super)] in
179 let types = Option.value_map this_ty ~default:types
180 ~f:(fun ty -> Log_type ("this_ty", ty) :: types) in
181 log_types (Reason.to_pos (fst ty_sub)) env
182 [Log_head ("Typing_subtype." ^ function_name, types)]
183 end)
185 let is_final_and_not_contravariant env id =
186 let class_def = Env.get_class env id in
187 match class_def with
188 | Some class_ty -> TUtils.class_is_final_and_not_contravariant class_ty
189 | None -> false
191 (* Process the constraint proposition *)
192 let rec process_simplify_subtype_result ~this_ty ~fail env prop =
193 match prop with
194 | TL.Unsat f ->
195 f ();
197 | TL.IsSubtype (ty1, ty2) -> sub_type_inner_helper env ~this_ty ty1 ty2
198 | TL.IsEqual (ty1, ty2) ->
199 (* These come only from invariant generics, with new_inference=false *)
200 fst (Unify.unify env ty2 ty1)
201 | TL.Conj props ->
202 (* Evaluates list from left-to-right so preserves order of conjuncts *)
203 List.fold_left
204 ~init:env
205 ~f:(process_simplify_subtype_result ~this_ty ~fail)
206 props
207 | TL.Disj [prop] ->
208 process_simplify_subtype_result ~this_ty ~fail env prop
210 | TL.Disj props ->
211 let rec try_disj props =
212 match props with
213 | [] ->
214 fail ();
216 | prop :: props ->
217 Errors.try_ begin fun () ->
218 process_simplify_subtype_result ~this_ty ~fail env prop end
219 (fun _ -> try_disj props)
221 try_disj props
223 (* Attempt to "solve" a subtype assertion ty_sub <: ty_super.
224 * Return a proposition that is equivalent, but simpler, than
225 * the original assertion. Fail with Unsat error_function if
226 * the assertion is unsatisfiable. Some examples:
227 * string <: arraykey ==> True (represented as Conj [])
228 * (For covariant C and a type variable v)
229 * C<string> <: C<v> ==> string <: v
230 * (Assuming that C does *not* implement interface J)
231 * C <: J ==> Unsat _
232 * (Assuming we have T <: D in tpenv, and class D implements I)
233 * vec<T> <: vec<I> ==> True
234 * This last one would be left as T <: I if seen_generic_params is None
236 and simplify_subtype
237 ~(seen_generic_params : SSet.t option)
238 ?(deep : bool = true)
239 ~(no_top_bottom : bool)
240 ?(this_ty : locl ty option = None)
241 (ty_sub : locl ty)
242 (ty_super : locl ty)
243 env : Env.env * TL.subtype_prop =
244 log_subtype ~this_ty "simplify_subtype" env ty_sub ty_super;
245 let new_inference = TypecheckerOptions.new_inference (Env.get_tcopt env) in
246 let env, ety_super = Env.expand_type env ty_super in
247 let env, ety_sub = Env.expand_type env ty_sub in
248 let uerror () = TUtils.uerror env (fst ety_super) (snd ety_super) (fst ety_sub) (snd ety_sub) in
249 (* We *know* that the assertion is unsatisfiable *)
250 let invalid_with f = env, TL.Unsat f in
251 let invalid () = invalid_with uerror in
252 let invalid_env_with env f = env, TL.Unsat f in
253 let invalid_env env = invalid_env_with env uerror in
254 (* We *know* that the assertion is valid *)
255 let valid () = env, TL.valid in
256 (* We don't know whether the assertion is valid or not *)
257 let default () =
258 if new_inference
259 then env, TL.IsSubtype (ety_sub, ety_super)
260 else env, TL.IsSubtype (ty_sub, ty_super) in
261 let simplify_subtype = simplify_subtype ~no_top_bottom in
262 let simplify_subtype_funs = simplify_subtype_funs ~no_top_bottom in
263 let simplify_subtype_variance = simplify_subtype_variance ~no_top_bottom in
264 let simplify_subtype_generic_sub name_sub opt_sub_cstr ty_super env =
265 begin match seen_generic_params with
266 | None -> default ()
267 | Some seen ->
268 (* If we've seen this type parameter before then we must have gone
269 * round a cycle so we fail
271 if SSet.mem name_sub seen
272 then invalid ()
273 else
274 (* If the generic is actually an expression dependent type,
275 we need to update this_ty
277 let this_ty = if AbstractKind.is_generic_dep_ty name_sub &&
278 Option.is_none this_ty then Some ety_sub else this_ty in
279 let seen_generic_params = Some (SSet.add name_sub seen) in
280 (* Otherwise, we collect all the upper bounds ("as" constraints) on
281 the generic parameter, and check each of these in turn against
282 ty_super until one of them succeeds
284 let rec try_bounds tyl env =
285 match tyl with
286 | [] ->
287 (* Try an implicit mixed = ?nonnull bound before giving up.
288 This can be useful when checking T <: t, where type t is
289 equivalent to but syntactically different from ?nonnull.
290 E.g., if t is a generic type parameter T with nonnull as
291 a lower bound.
293 let r = Reason.Rimplicit_upper_bound (Reason.to_pos (fst ety_sub), "?nonnull") in
294 let tmixed = MakeType.mixed r in
295 env |>
296 simplify_subtype ~seen_generic_params ~deep ~this_ty tmixed ty_super
298 | [ty] ->
299 env |>
300 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super
302 | ty::tyl ->
303 env |>
304 try_bounds tyl |||
305 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super
307 env |>
308 try_bounds (Option.to_list opt_sub_cstr
309 @ Typing_set.elements (Env.get_upper_bounds env name_sub)) |>
310 (* Turn error into a generic error about the type parameter *)
311 if_unsat invalid
312 end in
314 let simplify_subtype_generic_super ty_sub name_super env =
315 begin match seen_generic_params with
316 | None -> default ()
317 | Some seen ->
319 (* If we've seen this type parameter before then we must have gone
320 * round a cycle so we fail
322 if SSet.mem name_super seen
323 then invalid ()
324 else
325 let seen_generic_params = Some (SSet.add name_super seen) in
326 (* Collect all the lower bounds ("super" constraints) on the
327 * generic parameter, and check ty_sub against each of them in turn
328 * until one of them succeeds *)
329 let rec try_bounds tyl env =
330 match tyl with
331 | [] ->
332 invalid ()
334 | ty::tyl ->
335 env |>
336 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub ty |||
337 try_bounds tyl
339 (* Turn error into a generic error about the type parameter *)
340 env |>
341 try_bounds (Typing_set.elements (Env.get_lower_bounds env name_super)) |>
342 if_unsat invalid
343 end in
345 match snd ety_sub, snd ety_super with
346 | Tvar _ ,_ | _, Tvar _ when not new_inference -> assert false
348 | Tvar var_sub, Tvar var_super when var_sub = var_super -> valid ()
350 (* Internally, newtypes and dependent types are always equipped with an upper bound.
351 * In the case when no upper bound is specified in source code,
352 * an implicit upper bound mixed = ?nonnull is added.
354 | Tabstract ((AKnewtype _ | AKdependent _), None), _
355 | _, Tabstract ((AKnewtype _ | AKdependent _), None) -> assert false
357 | Terr, _ | _, Terr -> if no_top_bottom then default () else valid ()
359 | (Tprim Nast.(Tint | Tbool | Tfloat | Tstring | Tresource | Tnum |
360 Tarraykey | Tnoreturn) |
361 Tnonnull | Tfun _ | Ttuple _ | Tshape _ | Tabstract (AKenum _, _) |
362 Tanon _ | Tobject | Tclass _ | Tarraykind _),
363 Tnonnull ->
364 valid ()
365 | (Tdynamic | Toption _ | Tprim Nast.(Tnull | Tvoid)),
366 Tnonnull ->
367 invalid ()
369 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tnonnull ->
370 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
372 | Tdynamic, Tdynamic ->
373 valid ()
374 | (Tnonnull | Toption _ | Tprim _ | Tfun _ | Ttuple _ | Tshape _ |
375 Tabstract (AKenum _, _) | Tanon _ | Tobject | Tclass _ | Tarraykind _),
376 Tdynamic ->
377 invalid ()
378 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tdynamic ->
379 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
381 (* everything subtypes mixed *)
382 | _, Toption (_, Tnonnull) -> valid ()
383 (* null is the type of null and is a subtype of any option type. *)
384 | Tprim Nast.Tnull, Toption _ -> valid ()
385 (* void behaves with respect to subtyping as an abstract type with
386 * an implicit upper bound ?nonnull
388 | Tprim Nast.Tvoid, Toption ty_super' ->
389 let r = Reason.Rimplicit_upper_bound (Reason.to_pos (fst ety_sub), "?nonnull") in
390 let tmixed = MakeType.mixed r in
391 env |>
392 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub ty_super' |||
393 simplify_subtype ~seen_generic_params ~deep ~this_ty tmixed ty_super
394 | Tdynamic, Toption ty_super ->
395 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub ty_super env
396 (* ?ty_sub' <: ?ty_super' iff ty_sub' <: ?ty_super'. Reasoning:
397 * If ?ty_sub' <: ?ty_super', then from ty_sub' <: ?ty_sub' (widening) and transitivity
398 * of <: it follows that ty_sub' <: ?ty_super'. Conversely, if ty_sub' <: ?ty_super', then
399 * by covariance and idempotence of ?, we have ?ty_sub' <: ??ty_sub' <: ?ty_super'.
400 * Therefore, this step preserves the set of solutions.
402 | Toption ty_sub', Toption _ ->
403 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub' ty_super env
404 (* If ty_sub <: ?ty_super' and ty_sub does not contain null then we
405 * must also have ty_sub <: ty_super'. The converse follows by
406 * widening and transitivity. Therefore, this step preserves the set
407 * of solutions.
409 | (Tprim Nast.(Tint | Tbool | Tfloat | Tstring | Tresource | Tnum |
410 Tarraykey | Tnoreturn) |
411 Tnonnull | Tfun _ | Ttuple _ | Tshape _ | Tanon _ | Tobject |
412 Tclass _ | Tarraykind _ | Tabstract (AKenum _, _) | Tany),
413 Toption ty_super' ->
414 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub ty_super' env
415 | Tabstract (AKnewtype (name_sub, _), _),
416 Toption (_, Tabstract (AKnewtype (name_super, _), _) as ty_super')
417 when name_super = name_sub ->
418 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub ty_super' env
420 | Tabstract (AKdependent d_sub, Some bound_sub),
421 Tabstract (AKdependent d_super, Some bound_super) ->
422 let this_ty = Option.first_some this_ty (Some ety_sub) in
423 (* Dependent types are identical but bound might be different *)
424 if d_sub = d_super
425 then simplify_subtype ~seen_generic_params ~deep ~this_ty bound_sub bound_super env
426 else simplify_subtype ~seen_generic_params ~deep ~this_ty bound_sub ty_super env
428 (* This is sort of a hack because our handling of Toption is highly
429 * dependent on how the type is structured. When we see a bare
430 * dependent type we strip it off at this point since it shouldn't be
431 * relevant to subtyping any more.
434 | Tabstract (AKdependent (`expr _, []), Some ty_sub), (Tclass _ | Toption _) ->
435 let this_ty = Option.first_some this_ty (Some ety_sub) in
436 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub ty_super env
438 (* If t1 <: ?t2 and t1 is an abstract type constrained as t1',
439 * then t1 <: t2 or t1' <: ?t2. The converse is obviously
440 * true as well. We can fold the case where t1 is unconstrained
441 * into the case analysis below.
443 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Toption arg_ty_super ->
444 env |>
445 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub arg_ty_super |||
446 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super
447 (* If t1 <: ?t2, where t1 is guaranteed not to contain null, then
448 * t1 <: t2, and the converse is obviously true as well.
450 | Tabstract (AKgeneric name_sub, opt_sub_cstr), Toption arg_ty_super
451 when Option.is_some seen_generic_params ->
452 env |>
453 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub arg_ty_super |||
454 (* Look up *)
455 simplify_subtype_generic_sub name_sub opt_sub_cstr ty_super
457 | Tprim (Nast.Tint | Nast.Tfloat), Tprim Nast.Tnum -> valid ()
458 | Tprim (Nast.Tint | Nast.Tstring), Tprim Nast.Tarraykey -> valid ()
459 | Tprim p1, Tprim p2 ->
460 if p1 = p2 then valid () else invalid ()
461 | Tabstract ((AKenum _), _), Tprim Nast.Tarraykey ->
462 valid ()
463 | (Tnonnull | Tdynamic | Tfun _ | Ttuple _ | Tshape _ | Tanon _ |
464 Tabstract (AKenum _, None) | Tobject | Tclass _ | Tarraykind _),
465 Tprim _ ->
466 invalid ()
467 | Toption _,
468 Tprim Nast.(Tvoid | Tint | Tbool | Tfloat | Tstring | Tresource | Tnum |
469 Tarraykey | Tnoreturn) ->
470 invalid ()
471 | Toption ty_sub', Tprim Nast.Tnull ->
472 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub' ty_super env
473 | Tabstract ((AKnewtype _ | AKenum _ | AKdependent _), Some ty), Tprim _ ->
474 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
476 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Ttuple _ | Tshape _ |
477 Tabstract (AKenum _, _) | Tobject | Tclass _ | Tarraykind _), Tfun _ ->
478 invalid ()
479 | Tfun ft_sub, Tfun ft_super ->
480 let r_sub, r_super = fst ety_sub, fst ety_super in
481 simplify_subtype_funs ~seen_generic_params ~deep ~check_return:true
482 r_sub ft_sub r_super ft_super env
483 | Tanon (anon_arity, id), Tfun ft ->
484 let r_sub, r_super = fst ety_sub, fst ety_super in
485 begin match Env.get_anonymous env id with
486 | None ->
487 invalid_with (fun () -> Errors.anonymous_recursive_call (Reason.to_pos r_sub))
488 | Some (reactivity, is_coroutine, ftys, _, anon) ->
489 let p_super = Reason.to_pos r_super in
490 let p_sub = Reason.to_pos r_sub in
491 (* Add function type to set of types seen so far *)
492 ftys := TUtils.add_function_type env ety_super !ftys;
493 (env, TL.valid) |>
494 check_with (subtype_reactivity env reactivity ft.ft_reactive
495 || TypecheckerOptions.unsafe_rx (Env.get_tcopt env))
496 (fun () -> Errors.fun_reactivity_mismatch
497 p_super (TUtils.reactivity_to_string env reactivity)
498 p_sub (TUtils.reactivity_to_string env ft.ft_reactive)) |>
499 check_with (is_coroutine = ft.ft_is_coroutine) (fun () ->
500 Errors.coroutinness_mismatch ft.ft_is_coroutine p_super p_sub) |>
501 check_with (Unify.unify_arities
502 ~ellipsis_is_variadic:true anon_arity ft.ft_arity)
503 (fun () -> Errors.fun_arity_mismatch p_super p_sub) |>
504 (fun (env, prop) ->
505 let env, _, ret = anon env ft.ft_params ft.ft_arity in
506 (env, prop) &&&
507 simplify_subtype ~seen_generic_params ~deep ~this_ty ret ft.ft_ret)
509 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tfun _ ->
510 let this_ty = Option.first_some this_ty (Some ety_sub) in
511 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
513 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Tfun _ | Tshape _ |
514 Tabstract (AKenum _, _) | Tanon _ | Tobject | Tclass _ | Tarraykind _),
515 Ttuple _ ->
516 invalid ()
517 (* (t1,...,tn) <: (u1,...,un) iff t1<:u1, ... , tn <: un *)
518 | Ttuple tyl_sub, Ttuple tyl_super ->
519 if List.length tyl_super = List.length tyl_sub
520 then
521 wfold_left2 (fun res ty_sub ty_super -> res
522 &&& simplify_subtype ~seen_generic_params ~deep ty_sub ty_super)
523 (env, TL.valid) tyl_sub tyl_super
524 else invalid ()
525 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Ttuple _ ->
526 let this_ty = Option.first_some this_ty (Some ety_sub) in
527 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
529 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Tfun _ | Ttuple _ |
530 Tabstract (AKenum _, _) | Tanon _ | Tobject | Tclass _ | Tarraykind _),
531 Tshape _ ->
532 invalid ()
533 | Tshape (fields_known_sub, fdm_sub), Tshape (fields_known_super, fdm_super) ->
534 let r_sub, r_super = fst ety_sub, fst ety_super in
536 * shape_field_type A <: shape_field_type B iff:
537 * 1. A is no more optional than B
538 * 2. A's type <: B.type
540 let on_common_field
541 (env, acc) name
542 { sft_optional = optional_super; sft_ty = ty_super }
543 { sft_optional = optional_sub; sft_ty = ty_sub } =
544 match optional_super, optional_sub with
545 | true, _ | false, false ->
546 (env, acc) &&& simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub ty_super
547 | false, true ->
548 (env, acc) |> with_error (fun () -> Errors.required_field_is_optional
549 (Reason.to_pos r_sub)
550 (Reason.to_pos r_super)
551 (Env.get_shape_field_name name)) in
552 let on_missing_omittable_optional_field res _ _ = res in
553 let on_missing_non_omittable_optional_field
554 res name { sft_ty = ty_super; _ } =
555 let r = Reason.Rmissing_optional_field (
556 Reason.to_pos r_sub,
557 TUtils.get_printable_shape_field_name name
558 ) in
559 res &&& simplify_subtype ~seen_generic_params ~deep ~this_ty (MakeType.mixed r) ty_super in
560 TUtils.apply_shape
561 ~on_common_field
562 ~on_missing_omittable_optional_field
563 ~on_missing_non_omittable_optional_field
564 ~on_error:(fun _ f -> invalid_with f)
565 (env, TL.valid)
566 (r_super, fields_known_super, fdm_super)
567 (r_sub, fields_known_sub, fdm_sub)
568 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tshape _ ->
569 let this_ty = Option.first_some this_ty (Some ety_sub) in
570 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
572 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Tfun _ | Ttuple _ | Tshape _ |
573 Tabstract (AKenum _, None) | Tanon _ | Tobject | Tclass _ | Tarraykind _),
574 Tabstract (AKnewtype _, _) ->
575 invalid ()
576 | Tabstract (AKnewtype (name_sub, tyl_sub), _),
577 Tabstract (AKnewtype (name_super, tyl_super), _)
578 when name_super = name_sub ->
579 let td = Env.get_typedef env name_super in
580 begin match td with
581 | Some {td_tparams; _} ->
582 let variancel = List.map td_tparams (fun t -> t.tp_variance) in
583 simplify_subtype_variance ~seen_generic_params ~deep name_sub variancel tyl_sub tyl_super env
584 | None ->
585 invalid ()
587 | Tabstract ((AKnewtype _ | AKenum _ | AKdependent _), Some ty), Tabstract (AKnewtype _, _) ->
588 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
590 | Tabstract (AKenum e_sub, _), Tabstract (AKenum e_super, _)
591 when e_sub = e_super -> valid ()
592 | Tclass ((_, class_name), _, _), Tabstract (AKenum enum_name, _)
593 when enum_name = class_name -> valid ()
594 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Tfun _ | Ttuple _ | Tshape _ |
595 Tanon _ | Tobject | Tclass _ | Tarraykind _),
596 Tabstract (AKenum _, _) ->
597 invalid ()
598 | Tabstract (AKenum _, None), Tabstract (AKenum _, _) -> invalid ()
599 | Tabstract ((AKnewtype _ | AKenum _ | AKdependent _), Some ty), Tabstract (AKenum _, _) ->
600 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
602 | _, Tabstract (AKdependent _, Some (_, Tclass ((_, x), _, _) as ty))
603 when is_final_and_not_contravariant env x ->
604 (* For final class C, there is no difference between `this as X` and `X`,
605 * and `expr<#n> as X` and `X`.
606 * But we need to take care with contravariant classes, since we can't
607 * statically guarantee their runtime type.
609 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub ty env
611 (* Primitives and other concrete types cannot be subtypes of dependent types *)
612 | (Tnonnull | Tdynamic | Tprim _ | Tfun _ | Ttuple _ | Tshape _ |
613 Tabstract (AKenum _, None) | Tanon _ | Tclass _ | Tobject | Tarraykind _),
614 Tabstract (AKdependent (expr_dep, _), tyopt) ->
615 (* If the bound is the same class try and show more explanation of the error *)
616 begin match snd ty_sub, tyopt with
617 | Tclass ((_, y), _, _), Some (_, (Tclass ((_, x) as id, _, _))) when y = x ->
618 invalid_with (fun () ->
619 Errors.try_ uerror
620 (fun error ->
621 let p = Reason.to_pos (fst ety_sub) in
622 if expr_dep = `cls x
623 then Errors.exact_class_final id p error
624 else Errors.this_final id p error))
625 | _ -> invalid ()
628 | Tabstract ((AKnewtype _ | AKenum _), Some ty), Tabstract (AKdependent _, _) ->
629 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
630 | Toption _, Tabstract (AKdependent _, Some _) ->
631 invalid ()
633 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Ttuple _ | Tshape _ |
634 Tabstract (AKenum _, _) | Tobject | Tclass _ | Tarraykind _),
635 Tanon _ ->
636 invalid ()
637 | Tanon (_, id1), Tanon (_, id2) -> if id1 = id2 then valid () else invalid ()
638 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tanon _ ->
639 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
640 | Tfun _, Tanon _ ->
641 invalid ()
643 | Tobject, Tobject -> valid ()
644 (* Any class type is a subtype of object *)
645 | Tclass _, Tobject -> valid ()
646 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Tfun _ | Ttuple _ | Tshape _ |
647 Tabstract (AKenum _, _) | Tanon _ | Tarraykind _),
648 Tobject ->
649 invalid ()
650 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tobject ->
651 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
653 | Tabstract (AKenum _, _), Tclass ((_, class_name), _, [ty_super'])
654 when class_name = SN.Classes.cHH_BuiltinEnum ->
655 env |>
656 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub ty_super' &&&
657 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_super' ty_sub
658 | Tabstract (AKenum enum_name, None), Tclass ((_, class_name), exact, _) ->
659 if (enum_name = class_name || class_name = SN.Classes.cXHPChild) && exact = Nonexact
660 then valid ()
661 else invalid ()
662 | Tabstract (AKenum enum_name, Some ty), Tclass ((_, class_name), exact, _) ->
663 if enum_name = class_name && exact = Nonexact
664 then valid ()
665 else simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
666 | Tprim Nast.Tstring, Tclass ((_, class_name), exact, _) ->
667 if (class_name = SN.Classes.cStringish || class_name = SN.Classes.cXHPChild)
668 && exact = Nonexact
669 then valid ()
670 else invalid ()
671 | Tprim Nast.(Tarraykey | Tint | Tfloat | Tnum), Tclass ((_, class_name), exact, _) ->
672 if class_name = SN.Classes.cXHPChild && exact = Nonexact then valid () else invalid ()
673 | (Tnonnull | Tdynamic | Tprim Nast.(Tnull | Tvoid | Tbool | Tresource | Tnoreturn) |
674 Toption _ | Tfun _ | Ttuple _ | Tshape _ | Tanon _),
675 Tclass _ ->
676 invalid ()
677 (* Match what's done in unify for non-strict code *)
678 | Tobject, Tclass _ ->
679 if Env.is_strict env then invalid () else valid ()
680 | Tclass (x_sub, exact_sub, tyl_sub), Tclass (x_super, exact_super, tyl_super) ->
681 let exact_match =
682 match exact_sub, exact_super with
683 | Nonexact, Exact -> false
684 | _, _ -> true in
685 let p_sub, p_super = fst ety_sub, fst ety_super in
686 let cid_super, cid_sub = (snd x_super), (snd x_sub) in
687 (* This is side-effecting as it registers a dependency *)
688 let class_def_sub = Env.get_class env cid_sub in
689 if cid_super = cid_sub
690 then
691 (* If class is final then exactness is superfluous *)
692 let is_final =
693 match class_def_sub with
694 | Some tc -> Cls.final tc
695 | None -> false in
696 if not (exact_match || is_final)
697 then invalid ()
698 else
699 (* We handle the case where a generic A<T> is used as A *)
700 let tyl_super =
701 if List.is_empty tyl_super && not (Env.is_strict env)
702 then List.map tyl_sub (fun _ -> (p_super, Tany))
703 else tyl_super in
704 let tyl_sub =
705 if List.is_empty tyl_sub && not (Env.is_strict env)
706 then List.map tyl_super (fun _ -> (p_super, Tany))
707 else tyl_sub in
708 if List.length tyl_sub <> List.length tyl_super
709 then begin
710 let n_sub = String_utils.soi (List.length tyl_sub) in
711 let n_super = String_utils.soi (List.length tyl_super) in
712 invalid_with (fun () ->
713 Errors.type_arity_mismatch (fst x_super) n_super (fst x_sub) n_sub)
715 else
716 if List.is_empty tyl_sub && List.is_empty tyl_super
717 then valid ()
718 else
719 let variancel =
720 match class_def_sub with
721 | None ->
722 List.map tyl_sub (fun _ -> Ast.Invariant)
723 | Some class_sub ->
724 List.map (Cls.tparams class_sub) (fun t -> t.tp_variance) in
726 (* C<t1, .., tn> <: C<u1, .., un> iff
727 * t1 <:v1> u1 /\ ... /\ tn <:vn> un
728 * where vi is the variance of the i'th generic parameter of C,
729 * and <:v denotes the appropriate direction of subtyping for variance v
731 simplify_subtype_variance ~seen_generic_params ~deep
732 cid_sub variancel tyl_sub tyl_super env
733 else
734 if not exact_match
735 then invalid ()
736 else
737 begin match class_def_sub with
738 | None ->
739 (* This should have been caught already in the naming phase *)
740 valid ()
742 | Some class_sub ->
743 (* We handle the case where a generic A<T> is used as A *)
744 let tyl_sub =
745 if List.is_empty tyl_sub && not (Env.is_strict env)
746 then List.map (Cls.tparams class_sub) (fun _ -> (p_sub, Tany))
747 else tyl_sub in
748 if List.length (Cls.tparams class_sub) <> List.length tyl_sub
749 then
750 invalid_with (fun () ->
751 Errors.expected_tparam ~definition_pos:(Cls.pos class_sub)
752 ~use_pos:(Reason.to_pos p_sub) (List.length (Cls.tparams class_sub)))
753 else
754 let ety_env =
756 type_expansions = [];
757 substs = Subst.make (Cls.tparams class_sub) tyl_sub;
758 (* TODO: do we need this? *)
759 this_ty = Option.value this_ty ~default:ty_sub;
760 from_class = None;
761 validate_dty = None;
762 } in
763 let up_obj = Cls.get_ancestor class_sub cid_super in
764 match up_obj with
765 | Some up_obj ->
766 let env, up_obj = Phase.localize ~ety_env env up_obj in
767 simplify_subtype ~seen_generic_params ~deep ~this_ty up_obj ty_super env
768 | None ->
769 if Cls.kind class_sub = Ast.Ctrait || Cls.kind class_sub = Ast.Cinterface then
770 let rec try_reqs reqs env =
771 match Sequence.next reqs with
772 | None ->
773 (* It's crucial that we don't lose updates to global_tpenv in env that were
774 * introduced by PHase.localize. TODO: avoid this requirement *)
775 invalid_env env
777 | Some ((_, req_type), reqs) ->
779 (* a trait is never the runtime type, but it can be used
780 * as a constraint if it has requirements for its using
781 * classes *)
782 let env, req_type = Phase.localize ~ety_env env req_type in
783 env |>
784 simplify_subtype ~seen_generic_params ~deep ~this_ty
785 (p_sub, snd req_type) ty_super
786 ||| try_reqs reqs
788 try_reqs (Cls.all_ancestor_reqs class_sub) env
789 else invalid ()
791 | Tabstract ((AKnewtype _), Some ty), Tclass _ ->
792 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
793 | Tarraykind _, Tclass ((_, class_name), Nonexact, _)
794 when class_name = SN.Classes.cXHPChild -> valid ()
795 | Tarraykind akind, Tclass ((_, coll), Nonexact, [tv_super])
796 when (coll = SN.Collections.cTraversable ||
797 coll = SN.Rx.cTraversable ||
798 coll = SN.Collections.cContainer) ->
799 (match akind with
800 (* array <: Traversable<t> and emptyarray <: Traversable<t> for any t *)
801 | AKany -> valid ()
802 | AKempty -> valid ()
803 (* vec<tv> <: Traversable<tv_super>
804 * iff tv <: tv_super
805 * Likewise for vec<tv> <: Container<tv_super>
806 * and map<_,tv> <: Traversable<tv_super>
807 * and map<_,tv> <: Container<tv_super>
809 | AKvarray tv
810 | AKvec tv
811 | AKdarray (_, tv)
812 | AKvarray_or_darray tv
813 | AKmap (_, tv) -> simplify_subtype ~seen_generic_params ~deep ~this_ty tv tv_super env
815 | Tarraykind akind, Tclass ((_, coll), Nonexact, [tk_super; tv_super])
816 when (coll = SN.Collections.cKeyedTraversable
817 || coll = SN.Rx.cKeyedTraversable
818 || coll = SN.Collections.cKeyedContainer) ->
819 let r = fst ety_sub in
820 (match akind with
821 | AKany -> valid ()
822 | AKempty -> valid ()
823 | AKvarray tv
824 | AKvec tv ->
825 env |>
826 simplify_subtype ~seen_generic_params ~deep ~this_ty (MakeType.int r) tk_super &&&
827 simplify_subtype ~seen_generic_params ~deep ~this_ty tv tv_super
828 | AKvarray_or_darray tv ->
829 let tk_sub = MakeType.arraykey (Reason.Rvarray_or_darray_key (Reason.to_pos r)) in
830 env |>
831 simplify_subtype ~seen_generic_params ~deep ~this_ty tk_sub tk_super &&&
832 simplify_subtype ~seen_generic_params ~deep ~this_ty tv tv_super
833 | AKdarray (tk, tv)
834 | AKmap (tk, tv) ->
835 env |>
836 simplify_subtype ~seen_generic_params ~deep ~this_ty tk tk_super &&&
837 simplify_subtype ~seen_generic_params ~deep ~this_ty tv tv_super
839 | Tarraykind _, Tclass _ -> invalid ()
840 | Tabstract (AKdependent _, Some ty), Tclass _ ->
841 let this_ty = Option.first_some this_ty (Some ety_sub) in
842 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
844 (* Arrays *)
845 | Ttuple _, Tarraykind AKany ->
846 if TypecheckerOptions.disallow_array_as_tuple (Env.get_tcopt env)
847 then invalid ()
848 else valid ()
849 | (Tnonnull | Tdynamic | Toption _ | Tprim _ | Tfun _ | Ttuple _ |
850 Tshape _ | Tabstract (AKenum _, _) | Tanon _ | Tobject | Tclass _),
851 Tarraykind _ ->
852 invalid ()
853 | Tabstract ((AKnewtype _ | AKdependent _), Some ty), Tarraykind _ ->
854 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super env
855 | Tarraykind ak_sub, Tarraykind ak_super ->
856 let r = fst ety_sub in
857 begin match ak_sub, ak_super with
858 (* An array of any kind is a subtype of an array of AKany *)
859 | _, AKany ->
860 valid ()
862 (* An empty array is a subtype of any array type *)
863 | AKempty, _ ->
864 valid ()
866 (* array is a subtype of varray_or_darray<_> *)
867 | AKany, AKvarray_or_darray (_, Tany) ->
868 valid ()
870 | AKany, _ ->
871 let safe_array = TypecheckerOptions.safe_array (Env.get_tcopt env) in
872 if safe_array then invalid () else valid ()
874 (* varray_or_darray<ty1> <: varray_or_darray<ty2> iff t1 <: ty2
875 But, varray_or_darray<ty1> is never a subtype of a vect-like array *)
876 | AKvarray_or_darray ty_sub, AKvarray_or_darray ty_super ->
877 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub ty_super env
879 | (AKvarray ty_sub | AKvec ty_sub),
880 (AKvarray ty_super | AKvec ty_super | AKvarray_or_darray ty_super) ->
881 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub ty_super env
883 | (AKdarray (tk_sub, tv_sub) | AKmap (tk_sub, tv_sub)),
884 (AKdarray (tk_super, tv_super) | AKmap (tk_super, tv_super)) ->
885 env |>
886 simplify_subtype ~seen_generic_params ~deep ~this_ty tk_sub tk_super &&&
887 simplify_subtype ~seen_generic_params ~deep ~this_ty tv_sub tv_super
889 | (AKdarray (tk_sub, tv_sub) | AKmap (tk_sub, tv_sub)),
890 (AKvarray_or_darray tv_super) ->
891 let tk_super = MakeType.arraykey (Reason.Rvarray_or_darray_key (Reason.to_pos (fst ety_super))) in
892 env |>
893 simplify_subtype ~seen_generic_params ~deep ~this_ty tk_sub tk_super &&&
894 simplify_subtype ~seen_generic_params ~deep ~this_ty tv_sub tv_super
896 | (AKvarray elt_ty | AKvec elt_ty), (AKdarray _ | AKmap _)
897 when not (TypecheckerOptions.safe_vector_array (Env.get_tcopt env)) ->
898 let int_reason = Reason.Ridx (Reason.to_pos r, Reason.Rnone) in
899 let int_type = MakeType.int int_reason in
900 simplify_subtype ~seen_generic_params ~deep ~this_ty
901 (r, Tarraykind (AKmap (int_type, elt_ty))) ty_super env
903 (* any other array subtyping is unsatisfiable *)
904 | _ ->
905 invalid ()
908 (* ty_sub <: union{ty_super'} iff ty_sub <: ty_super' *)
909 | _, Tunresolved [ty_super'] when deep ->
910 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub ty_super' env
912 (* t1 | ... | tn <: t
913 * if and only if
914 * t1 <: t /\ ... /\ tn <: t
915 * We want this even if t is a type variable e.g. consider
916 * int | v <: v
918 | Tunresolved tyl, _->
919 if new_inference
920 then
921 List.fold_left tyl ~init:(env, TL.valid) ~f:(fun res ty_sub ->
922 res &&& simplify_subtype ~seen_generic_params ~deep ty_sub ty_super)
923 else default ()
925 (* We want to treat nullable as a union with the same rule as above.
926 * This is only needed for Tvar on right; other cases are dealt with specially as
927 * derived rules.
929 | Toption t, Tvar _ when new_inference ->
930 env |>
931 simplify_subtype ~seen_generic_params ~deep ~this_ty t ty_super &&&
932 simplify_subtype ~seen_generic_params ~deep ~this_ty (MakeType.null (fst ety_sub)) ty_super
934 | Tvar _, _ | _, Tvar _ ->
935 default ()
937 (* Num is not atomic: it is equivalent to int|float. The rule below relies
938 * on ty_sub not being a union e.g. consider num <: arraykey | float, so
939 * we break out num first.
941 | Tprim Nast.Tnum, Tunresolved _ when new_inference ->
942 let r = fst ty_sub in
943 env |>
944 simplify_subtype ~seen_generic_params ~deep ~this_ty (MakeType.float r) ty_super &&&
945 simplify_subtype ~seen_generic_params ~deep ~this_ty (MakeType.int r) ty_super
947 | _, Tunresolved tyl ->
948 (* It's sound to reduce t <: t1 | t2 to (t <: t1) || (t <: t2). But
949 * not complete e.g. consider (t1 | t3) <: (t1 | t2) | (t2 | t3).
950 * But we deal with unions on the left first (see case above), so this
951 * particular situation won't arise.
952 * TODO: identify under what circumstances this reduction is complete.
954 if new_inference
955 then
956 let rec try_each tys env =
957 match tys with
958 | [] ->
959 invalid ()
961 | ty::tys ->
962 env |>
963 simplify_subtype ~seen_generic_params ~deep ~this_ty ty_sub ty
964 ||| try_each tys
966 try_each tyl env
967 else default ()
969 | _, Tany | Tany, _ ->
970 if new_inference && not no_top_bottom then valid () else default ()
972 (* If subtype and supertype are the same generic parameter, we're done *)
973 | Tabstract (AKgeneric name_sub, _), Tabstract (AKgeneric name_super, _)
974 when name_sub = name_super
975 -> valid ()
977 (* Supertype is generic parameter *and* subtype is a newtype with bound.
978 * We need to make this a special case because there is a *choice*
979 * of subtyping rule to apply. See details in the case of dependent type
980 * against generic parameter which is similar
982 | Tabstract (AKnewtype (_, _), Some ty), Tabstract (AKgeneric name_super, _)
983 when Option.is_some seen_generic_params ->
984 env |>
985 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super |||
986 simplify_subtype_generic_super ty_sub name_super
988 (* void behaves with respect to subtyping as an abstract type with
989 * an implicit upper bound ?nonnull
991 | Tprim Nast.Tvoid, Tabstract (AKgeneric name_super, _)
992 when Option.is_some seen_generic_params ->
993 let r = Reason.Rimplicit_upper_bound (Reason.to_pos (fst ety_sub), "?nonnull") in
994 let tmixed = (r, Toption (r, Tnonnull)) in
995 env |>
996 simplify_subtype ~seen_generic_params ~deep ~this_ty tmixed ty_super |||
997 simplify_subtype_generic_super ty_sub name_super
999 (* Supertype is generic parameter *and* subtype is dependent.
1000 * We need to make this a special case because there is a *choice*
1001 * of subtyping rule to apply.
1003 * Example. First suppose that we have the definition
1005 * abstract const type TC as C
1007 * (1) Now suppose we have to check
1008 * this::TC <: Tu
1009 * where we have the constraint
1010 * <Tu super C>.
1011 * Then it's necessary to apply the rule for AKdependent first, so we
1012 * reduce this problem to
1013 * C <: Tu
1014 * and then call sub_generic_params to deal with the type parameter.
1015 * (2) Alternatively, suppose we again have to check
1016 * this::TC <: Tu
1017 * but this time we have the constraint
1018 * <Tu super this::TC>.
1019 * Then if we first reduce the problem to C <: Tu we fail;
1020 * but if we also try sub_generic_params then we succeed, because
1021 * we end up checking this::TC <: this::TC.
1023 | Tabstract (AKdependent _, Some ty), Tabstract (AKgeneric name_super, _)
1024 when Option.is_some seen_generic_params ->
1025 env |>
1026 simplify_subtype_generic_super ty_sub name_super |||
1027 (let this_ty = Option.first_some this_ty (Some ety_sub) in
1028 simplify_subtype ~seen_generic_params ~deep ~this_ty ty ty_super)
1030 (* Subtype or supertype is generic parameter
1031 * We delegate these cases to a separate function in order to catch cycles
1032 * in constraints e.g. <T1 as T2, T2 as T3, T3 as T1>
1034 | Tabstract (AKgeneric name_sub, opt_sub_cstr), _ ->
1035 simplify_subtype_generic_sub name_sub opt_sub_cstr ty_super env
1037 | _, Tabstract (AKgeneric name_super, _) ->
1038 simplify_subtype_generic_super ty_sub name_super env
1040 and simplify_subtype_variance
1041 ~(seen_generic_params : SSet.t option)
1042 ~(deep : bool)
1043 ~(no_top_bottom : bool)
1044 (cid : string)
1045 (variancel : Ast.variance list)
1046 (children_tyl : locl ty list)
1047 (super_tyl : locl ty list)
1048 : Env.env -> Env.env * TL.subtype_prop
1049 = fun env ->
1050 let simplify_subtype = simplify_subtype ~no_top_bottom ~seen_generic_params
1051 ~deep ~this_ty:None in
1052 let simplify_subtype_variance = simplify_subtype_variance ~no_top_bottom
1053 ~seen_generic_params ~deep in
1054 match variancel, children_tyl, super_tyl with
1055 | [], _, _
1056 | _, [], _
1057 | _, _, [] -> valid env
1058 | variance :: variancel, child :: childrenl, super :: superl ->
1059 begin match variance with
1060 | Ast.Covariant ->
1061 simplify_subtype child super env
1062 | Ast.Contravariant ->
1063 let super = (Reason.Rcontravariant_generic (fst super,
1064 Utils.strip_ns cid), snd super) in
1065 simplify_subtype super child env
1066 | Ast.Invariant ->
1067 let super' = (Reason.Rinvariant_generic (fst super,
1068 Utils.strip_ns cid), snd super) in
1069 if deep
1070 then
1071 env |>
1072 simplify_subtype child super' &&&
1073 simplify_subtype super child
1074 else
1075 env, TL.IsEqual (child, super')
1076 end &&&
1077 simplify_subtype_variance cid variancel childrenl superl
1079 and simplify_subtype_params
1080 ~(seen_generic_params : SSet.t option)
1081 ~(deep : bool)
1082 ~(no_top_bottom : bool)
1083 ?(is_method : bool = false)
1084 ?(check_params_reactivity = false)
1085 ?(check_params_mutability = false)
1086 (subl : locl fun_param list)
1087 (superl : locl fun_param list)
1088 (variadic_sub_ty : locl ty option)
1089 (variadic_super_ty : locl ty option)
1090 env =
1092 let simplify_subtype = simplify_subtype ~seen_generic_params ~no_top_bottom ~deep in
1093 let simplify_subtype_params = simplify_subtype_params ~seen_generic_params
1094 ~no_top_bottom ~deep in
1095 let simplify_subtype_params_with_variadic = simplify_subtype_params_with_variadic
1096 ~seen_generic_params ~no_top_bottom ~deep in
1097 let simplify_supertype_params_with_variadic = simplify_supertype_params_with_variadic
1098 ~seen_generic_params ~no_top_bottom ~deep in
1099 match subl, superl with
1100 (* When either list runs out, we still have to typecheck that
1101 the remaining portion sub/super types with the other's variadic.
1102 For example, if
1103 ChildClass {
1104 public function a(int $x = 0, string ... $args) // superl = [int], super_var = string
1106 overrides
1107 ParentClass {
1108 public function a(string ... $args) // subl = [], sub_var = string
1110 , there should be an error because the first argument will be checked against
1111 int, not string that is, ChildClass::a("hello") would crash,
1112 but ParentClass::a("hello") wouldn't.
1114 Similarly, if the other list is longer, aka
1115 ChildClass extends ParentClass {
1116 public function a(mixed ... $args) // superl = [], super_var = mixed
1118 overrides
1119 ParentClass {
1120 //subl = [string], sub_var = string
1121 public function a(string $x = 0, string ... $args)
1123 It should also check that string is a subtype of mixed.
1125 | [], _ -> (match variadic_super_ty with
1126 | None -> valid env
1127 | Some ty -> simplify_supertype_params_with_variadic superl ty env)
1128 | _, [] -> (match variadic_sub_ty with
1129 | None -> valid env
1130 | Some ty -> simplify_subtype_params_with_variadic subl ty env)
1131 | sub :: subl, super :: superl ->
1132 env |>
1133 begin
1134 if check_params_reactivity
1135 then subtype_fun_params_reactivity sub super
1136 else valid
1137 end &&&
1138 begin
1139 if check_params_mutability
1140 then check_mutability
1141 ~is_receiver:false
1142 sub.fp_pos sub.fp_mutability super.fp_pos super.fp_mutability
1143 else valid
1144 end &&&
1146 fun env ->
1147 begin
1148 let { fp_type = ty_sub; _ } = sub in
1149 let { fp_type = ty_super; _ } = super in
1150 (* Check that the calling conventions of the params are compatible.
1151 * We don't currently raise an error for reffiness because function
1152 * hints don't support '&' annotations (enforce_ctpbr = false). *)
1153 Unify.unify_param_modes ~enforce_ctpbr:is_method sub super;
1154 Unify.unify_accept_disposable sub super;
1155 let env = { env with Env.pos = Reason.to_pos (fst ty_sub) } in
1156 match sub.fp_kind, super.fp_kind with
1157 | FPinout, FPinout ->
1158 (* Inout parameters are invariant wrt subtyping for function types. *)
1159 env |>
1160 simplify_subtype ty_super ty_sub &&&
1161 simplify_subtype ty_sub ty_super
1162 | _ ->
1163 env |>
1164 simplify_subtype ty_sub ty_super
1165 end &&&
1166 simplify_subtype_params ~is_method subl superl
1167 variadic_sub_ty variadic_super_ty
1169 and simplify_subtype_params_with_variadic
1170 ~(seen_generic_params : SSet.t option)
1171 ~(deep : bool)
1172 ~(no_top_bottom : bool)
1173 (subl : locl fun_param list)
1174 (variadic_ty : locl ty)
1175 env =
1176 let simplify_subtype = simplify_subtype ~seen_generic_params ~no_top_bottom ~deep in
1177 let simplify_subtype_params_with_variadic = simplify_subtype_params_with_variadic
1178 ~seen_generic_params ~no_top_bottom ~deep in
1179 match subl with
1180 | [] -> valid env
1181 | { fp_type = sub; _ } :: subl ->
1182 let env = { env with Env.pos = Reason.to_pos (fst sub) } in
1183 env |>
1184 simplify_subtype sub variadic_ty &&&
1185 simplify_subtype_params_with_variadic subl variadic_ty
1187 and simplify_supertype_params_with_variadic
1188 ~(seen_generic_params : SSet.t option)
1189 ~(deep : bool)
1190 ~(no_top_bottom : bool)
1191 (superl : locl fun_param list)
1192 (variadic_ty : locl ty)
1193 env =
1194 let simplify_subtype = simplify_subtype ~seen_generic_params ~no_top_bottom ~deep in
1195 let simplify_supertype_params_with_variadic = simplify_supertype_params_with_variadic
1196 ~seen_generic_params ~no_top_bottom ~deep in
1197 match superl with
1198 | [] -> valid env
1199 | { fp_type = super; _ } :: superl ->
1200 let env = { env with Env.pos = Reason.to_pos (fst super) } in
1201 env |>
1202 simplify_subtype variadic_ty super &&&
1203 simplify_supertype_params_with_variadic superl variadic_ty
1205 and subtype_reactivity
1206 ?(extra_info: reactivity_extra_info option)
1207 ?(is_call_site = false)
1208 (env : Env.env)
1209 (r_sub : reactivity)
1210 (r_super : reactivity) : bool =
1212 let maybe_localize t =
1213 match t with
1214 | DeclTy t ->
1215 let ety_env = Phase.env_with_self env in
1216 let _, t = Phase.localize ~ety_env env t in
1218 | LoclTy t -> t in
1220 let class_ty =
1221 Option.bind extra_info (fun { class_ty = cls; _ } ->
1222 Option.map cls ~f:maybe_localize) in
1224 (* for method declarations check if condition type for r_super includes
1225 reactive method with a matching name. If yes - then it will act as a guarantee
1226 that derived class will have to redefine the method with a shape required
1227 by condition type (reactivity of redefined method must be subtype of reactivity
1228 of method in interface) *)
1229 let condition_type_has_matching_reactive_method condition_type_super (method_name, is_static) =
1230 let m =
1231 ConditionTypes.try_get_method_from_condition_type
1232 env condition_type_super is_static method_name in
1233 match m with
1234 | Some { ce_type = lazy (_, Tfun f); _ } ->
1235 (* check that reactivity of interface method (effectively a promised
1236 reactivity of a method in derived class) is a subtype of r_super.
1237 NOTE: we check only for unconditional reactivity since conditional
1238 version does not seems to yield a lot and will requre implementing
1239 cycle detection for condition types *)
1240 begin match f.ft_reactive with
1241 | Reactive None | Shallow None | Local None ->
1242 let extra_info = {
1243 empty_extra_info with parent_class_ty = Some (DeclTy condition_type_super)
1244 } in
1245 subtype_reactivity ~extra_info env f.ft_reactive r_super
1246 | _ -> false
1248 | _ -> false in
1249 match r_sub, r_super, extra_info with
1250 (* anything is a subtype of nonreactive functions *)
1251 | _, Nonreactive, _ -> true
1252 (* to compare two maybe reactive values we need to unwrap them *)
1253 | MaybeReactive sub, MaybeReactive super, _ ->
1254 subtype_reactivity ?extra_info ~is_call_site env sub super
1255 (* for explicit checks at callsites implicitly unwrap maybereactive value:
1256 function f(<<__AtMostRxAsFunc>> F $f)
1257 f(<<__RxLocal>> () ==> {... })
1258 here parameter will be maybereactive and argument - rxlocal
1260 | sub, MaybeReactive super, _ when is_call_site ->
1261 subtype_reactivity ?extra_info ~is_call_site env sub super
1262 (* if is_call_site is falst ignore maybereactive flavors.
1263 This usually happens during subtype checks for arguments and when target
1264 function is conditionally reactive we'll do the proper check
1265 in typing_reactivity.check_call. *)
1266 | _, MaybeReactive _, _ when not is_call_site -> true
1267 (* ok:
1268 class A { function f((function(): int) $f) {} }
1269 class B extends A {
1270 <<__Rx>>
1271 function f(<<__AtMostRxAsFunc>> (function(): int) $f);
1273 reactivity for arguments is checked contravariantly *)
1274 | _, RxVar None, _
1275 (* ok:
1276 <<__Rx>>
1277 function f(<<__AtMostRxAsFunc>> (function(): int) $f) { return $f() } *)
1278 | RxVar None, RxVar _, _ -> true
1279 | RxVar (Some sub), RxVar (Some super), _
1280 | sub, RxVar (Some super), _ ->
1281 subtype_reactivity ?extra_info ~is_call_site env sub super
1282 | RxVar _, _, _ -> false
1283 | (Local cond_sub | Shallow cond_sub | Reactive cond_sub), Local cond_super, _
1284 | (Shallow cond_sub | Reactive cond_sub), Shallow cond_super, _
1285 | Reactive cond_sub, Reactive cond_super, _
1286 when subtype_param_rx_if_impl ~is_param:false env cond_sub class_ty cond_super ->
1287 true
1288 (* function type TSub of method M with arbitrary reactivity in derive class
1289 can be subtype of conditionally reactive function type TSuper of method M
1290 defined in base class when condition type has reactive method M.
1291 interface Rx {
1292 <<__Rx>>
1293 public function f(): int;
1295 class A {
1296 <<__RxIfImplements(Rx::class)>>
1297 public function f(): int { ... }
1299 class B extends A {
1300 public function f(): int { ... }
1302 This should be OK because:
1303 - B does not implement Rx (B::f is not compatible with Rx::f) which means
1304 that calling ($b : B)->f() will not be treated as reactive
1305 - if one of subclasses of B will decide to implement B - they will be forced
1306 to redeclare f which now will shadow B::f. Note that B::f will still be
1307 accessible as parent::f() but will be treated as non-reactive call.
1309 | _, (Reactive (Some t) | Shallow (Some t) | Local (Some t)), Some { method_info = Some mi; _ }
1310 when condition_type_has_matching_reactive_method t mi ->
1311 true
1312 (* call_site specific cases *)
1313 (* shallow can call into local *)
1314 | Local cond_sub, Shallow cond_super, _ when
1315 is_call_site &&
1316 subtype_param_rx_if_impl ~is_param:false env cond_sub class_ty cond_super ->
1317 true
1318 (* local can call into non-reactive *)
1319 | Nonreactive, Local _, _ when is_call_site -> true
1320 | _ -> false
1322 and should_check_fun_params_reactivity
1323 (ft_super: locl fun_type) = ft_super.ft_reactive <> Nonreactive
1325 (* checks condition described by OnlyRxIfImpl condition on parameter is met *)
1326 and subtype_param_rx_if_impl
1327 ~is_param
1328 (env: Env.env)
1329 (cond_type_sub: decl ty option)
1330 (declared_type_sub: locl ty option)
1331 (cond_type_super: decl ty option) =
1332 let cond_type_sub =
1333 Option.map cond_type_sub ~f:(ConditionTypes.localize_condition_type env) in
1334 let cond_type_super =
1335 Option.map cond_type_super ~f:(ConditionTypes.localize_condition_type env) in
1336 match cond_type_sub, cond_type_super with
1337 (* no condition types - do nothing *)
1338 | None, None -> true
1339 (* condition type is specified only for super - ok for receiver case (is_param is false)
1340 abstract class A {
1341 <<__RxLocal, __OnlyRxIfImpl(Rx1::class)>>
1342 public abstract function condlocalrx(): int;
1344 abstract class B extends A {
1345 // ok to override cond local with local (if condition is not met - method
1346 // in base class is non-reactive )
1347 <<__Override, __RxLocal>>
1348 public function condlocalrx(): int {
1349 return 1;
1352 for parameters we need to verify that declared type of sub is a subtype of
1353 conditional type for super. Here is an example where this is violated:
1355 interface A {}
1356 interface RxA {}
1358 class C1 {
1359 <<__Rx>>
1360 public function f(A $a): void {
1364 class C2 extends C1 {
1365 // ERROR: invariant f body is reactive iff $a instanceof RxA can be violated
1366 <<__Rx, __AtMostRxAsArgs>>
1367 public function f(<<__OnlyRxIfImpl(RxA::class)>>A $a): void {
1370 here declared type of sub is A
1371 and cond type of super is RxA
1373 | None, Some _ when not is_param -> true
1374 | None, Some cond_type_super ->
1375 Option.value_map declared_type_sub
1376 ~default:false
1377 ~f:(fun declared_type_sub -> is_sub_type env declared_type_sub cond_type_super)
1378 (* condition types are set for both sub and super types: contravariant check
1379 interface A {}
1380 interface B extends A {}
1381 interface C extends B {}
1383 interface I1 {
1384 <<__Rx, __OnlyRxIfImpl(B::class)>>
1385 public function f(): void;
1386 <<__Rx>>
1387 public function g(<<__OnlyRxIfImpl(B::class)>> A $a): void;
1389 interface I2 extends I1 {
1390 // OK since condition in I1::f covers I2::f
1391 <<__Rx, __OnlyRxIfImpl(A::class)>>
1392 public function f(): void;
1393 // OK since condition in I1::g covers I2::g
1394 <<__Rx>>
1395 public function g(<<__OnlyRxIfImpl(A::class)>> A $a): void;
1397 interface I3 extends I1 {
1398 // Error since condition in I1::f is less strict that in I3::f
1399 <<__Rx, __OnlyRxIfImpl(C::class)>>
1400 public function f(): void;
1401 // Error since condition in I1::g is less strict that in I3::g
1402 <<__Rx>>
1403 public function g(<<__OnlyRxIfImpl(C::class)>> A $a): void;
1406 | Some cond_type_sub, Some cond_type_super ->
1407 is_sub_type env cond_type_super cond_type_sub
1408 (* condition type is set for super type, check if declared type of
1409 subtype is a subtype of condition type
1410 interface Rx {
1411 <<__Rx>>
1412 public function f(int $a): void;
1414 class A<T> {
1415 <<__Rx, __OnlyRxIfImpl(Rx::class)>>
1416 public function f(T $a): void {
1419 // B <: Rx so B::f is completely reactive
1420 class B extends A<int> implements Rx {
1421 } *)
1422 | Some cond_type_sub, None ->
1423 Option.value_map declared_type_sub
1424 ~default:false
1425 ~f:(fun declared_type_sub -> is_sub_type env declared_type_sub cond_type_sub)
1427 (* checks reactivity conditions for function parameters *)
1428 and subtype_fun_params_reactivity
1429 (p_sub: locl fun_param)
1430 (p_super: locl fun_param)
1431 env =
1432 match p_sub.fp_rx_annotation, p_super.fp_rx_annotation with
1433 (* no conditions on parameters - do nothing *)
1434 | None, None -> valid env
1435 (* both parameters are conditioned to be rx function - no need to check anything *)
1436 | Some Param_rx_var, Some Param_rx_var -> valid env
1437 | None, Some Param_rx_var ->
1438 (* parameter is conditionally reactive in supertype and missing condition
1439 in subtype - this is ok only if parameter in subtype is reactive
1440 <<__Rx>>
1441 function super((function(): int) $f);
1442 <<__Rx>>
1443 function sub(<<__AtMostRxAsFunc>> (function(): int) $f);
1444 We check if sub <: super. parameters are checked contravariantly
1445 so we need to verify that
1446 (function(): int) $f <: <<__AtMostRxAsFunc>> (function(): int) $f
1448 Suppose this is legal, then this will be allowed (in pseudo-code)
1450 function sub(<<__AtMostRxAsFunc>> (function(): int) $f) {
1451 $f(); // can call function here since it is conditionally reactive
1453 <<__Rx>>
1454 function g() {
1455 $f: super = sub;
1456 // invoke non-reactive code in reactive context which is bad
1457 $f(() ==> { echo 1; });
1460 It will be safe if parameter in super will be completely reactive,
1461 hence check below *)
1462 let _, p_sub_type = Env.expand_type env p_sub.fp_type in
1463 begin match p_sub_type with
1464 | _, Tfun tfun when tfun.ft_reactive <> Nonreactive -> valid env
1465 | _, Tfun _ ->
1466 env, TL.Unsat (fun () -> Errors.rx_parameter_condition_mismatch
1467 SN.UserAttributes.uaAtMostRxAsFunc p_sub.fp_pos p_super.fp_pos)
1468 (* parameter type is not function - error will be reported in different place *)
1469 | _ -> valid env
1471 | cond_sub, cond_super ->
1472 let cond_type_sub =
1473 match cond_sub with
1474 | Some (Param_rx_if_impl t) -> Some t
1475 | _ -> None in
1476 let cond_type_super =
1477 match cond_super with
1478 | Some (Param_rx_if_impl t) -> Some t
1479 | _ -> None in
1480 let ok =
1481 subtype_param_rx_if_impl ~is_param:true env cond_type_sub (Some p_sub.fp_type)
1482 cond_type_super in
1483 check_with ok (fun () ->
1484 Errors.rx_parameter_condition_mismatch
1485 SN.UserAttributes.uaOnlyRxIfImpl p_sub.fp_pos p_super.fp_pos) (env, TL.valid)
1487 (* Helper function for subtyping on function types: performs all checks that
1488 * don't involve actual types:
1489 * <<__ReturnDisposable>> attribute
1490 * <<__MutableReturn>> attribute
1491 * <<__Rx>> attribute
1492 * <<__Mutable>> attribute
1493 * whether or not the function is a coroutine
1494 * variadic arity
1496 and check_subtype_funs_attributes
1497 ?(extra_info: reactivity_extra_info option)
1498 (r_sub : Reason.t)
1499 (ft_sub : locl fun_type)
1500 (r_super : Reason.t)
1501 (ft_super : locl fun_type) env =
1502 let p_sub = Reason.to_pos r_sub in
1503 let p_super = Reason.to_pos r_super in
1504 (env, TL.valid) |>
1505 check_with
1506 (subtype_reactivity ?extra_info env ft_sub.ft_reactive ft_super.ft_reactive)
1507 (fun () -> Errors.fun_reactivity_mismatch
1508 p_super (TUtils.reactivity_to_string env ft_super.ft_reactive)
1509 p_sub (TUtils.reactivity_to_string env ft_sub.ft_reactive))
1511 check_with
1512 (ft_sub.ft_is_coroutine = ft_super.ft_is_coroutine)
1513 (fun () -> Errors.coroutinness_mismatch ft_super.ft_is_coroutine p_super p_sub) |>
1514 check_with
1515 (ft_sub.ft_return_disposable = ft_super.ft_return_disposable)
1516 (fun () -> Errors.return_disposable_mismatch ft_super.ft_return_disposable p_super p_sub) |>
1517 (* it is ok for subclass to return mutably owned value and treat it as immutable -
1518 the fact that value is mutably owned guarantees it has only single reference so
1519 as a result this single reference will be immutable. However if super type
1520 returns mutable value and subtype yields immutable value - this is not safe.
1521 NOTE: error is not reported if child is non-reactive since it does not have
1522 immutability-by-default behavior *)
1523 check_with
1524 (ft_sub.ft_returns_mutable = ft_super.ft_returns_mutable
1525 || not ft_super.ft_returns_mutable
1526 || ft_sub.ft_reactive = Nonreactive)
1527 (fun () -> Errors.mutable_return_result_mismatch ft_super.ft_returns_mutable p_super p_sub) |>
1528 check_with
1529 (ft_super.ft_reactive = Nonreactive
1530 || ft_super.ft_returns_void_to_rx
1531 || not ft_sub.ft_returns_void_to_rx)
1532 (fun () ->
1533 (* __ReturnsVoidToRx can be omitted on subtype, in this case using subtype
1534 via reference to supertype in rx context will be ok since result will be
1535 discarded. The opposite is not true:
1536 class A {
1537 <<__Rx, __Mutable>>
1538 public function f(): A { return new A(); }
1540 class B extends A {
1541 <<__Rx, __Mutable, __ReturnsVoidToRx>>
1542 public function f(): A { return $this; }
1545 <<__Rx, __MutableReturn>>
1546 function f(): A { return new B(); }
1547 $a = HH\Rx\mutable(f());
1548 $a1 = $a->f(); // immutable alias to mutable reference *)
1549 Errors.return_void_to_rx_mismatch ~pos1_has_attribute:true p_sub p_super) |>
1550 (* check mutability only for reactive functions *)
1551 let check_params_mutability =
1552 ft_super.ft_reactive <> Nonreactive &&
1553 ft_sub.ft_reactive <> Nonreactive in
1554 fun (env, prop) -> (if check_params_mutability
1555 (* check mutability of receivers *)
1556 then (env, prop) &&&
1557 check_mutability ~is_receiver:true
1558 p_super ft_super.ft_mutability p_sub ft_sub.ft_mutability else env, prop) |>
1559 check_with
1560 ((arity_min ft_sub.ft_arity) <= (arity_min ft_super.ft_arity))
1561 (fun () -> Errors.fun_too_many_args p_sub p_super)
1563 fun res -> (match ft_sub.ft_arity, ft_super.ft_arity with
1564 | Fellipsis _, Fvariadic _ ->
1565 (* The HHVM runtime ignores "..." entirely, but knows about
1566 * "...$args"; for contexts for which the runtime enforces method
1567 * compatibility (currently, inheritance from abstract/interface
1568 * methods), letting "..." override "...$args" would result in method
1569 * compatibility errors at runtime. *)
1570 with_error (fun () -> Errors.fun_variadicity_hh_vs_php56 p_sub p_super) res
1571 | Fstandard (_, sub_max), Fstandard (_, super_max) ->
1572 if sub_max < super_max
1573 then with_error (fun () -> Errors.fun_too_few_args p_sub p_super) res else res
1574 | Fstandard _, _ -> with_error (fun () -> Errors.fun_unexpected_nonvariadic p_sub p_super) res
1575 | _, _ -> res
1578 (* This implements basic subtyping on non-generic function types:
1579 * (1) return type behaves covariantly
1580 * (2) parameter types behave contravariantly
1581 * (3) special casing for variadics, and various reactivity and mutability attributes
1583 and simplify_subtype_funs
1584 ~(seen_generic_params : SSet.t option)
1585 ~(deep : bool)
1586 ~(no_top_bottom : bool)
1587 ~(check_return : bool)
1588 ?(extra_info: reactivity_extra_info option)
1589 (r_sub : Reason.t)
1590 (ft_sub : locl fun_type)
1591 (r_super : Reason.t)
1592 (ft_super : locl fun_type)
1594 : Env.env * TL.subtype_prop =
1595 let variadic_subtype = match ft_sub.ft_arity with
1596 | Fvariadic (_, {fp_type = var_sub; _ }) -> Some var_sub
1597 | _ -> None in
1598 let variadic_supertype = match ft_super.ft_arity with
1599 | Fvariadic (_, {fp_type = var_super; _ }) -> Some var_super
1600 | _ -> None in
1602 let simplify_subtype = simplify_subtype ~seen_generic_params ~no_top_bottom ~deep in
1603 let simplify_subtype_params = simplify_subtype_params ~seen_generic_params
1604 ~no_top_bottom ~deep in
1606 (* First apply checks on attributes, coroutine-ness and variadic arity *)
1607 env |>
1608 check_subtype_funs_attributes ?extra_info r_sub ft_sub r_super ft_super &&&
1610 (* Now do contravariant subtyping on parameters *)
1611 begin
1612 match variadic_subtype, variadic_supertype with
1613 | Some var_sub, Some var_super -> simplify_subtype var_super var_sub
1614 | _ -> valid
1615 end &&&
1617 begin
1618 let check_params_mutability =
1619 ft_super.ft_reactive <> Nonreactive &&
1620 ft_sub.ft_reactive <> Nonreactive in
1621 let is_method =
1622 (Option.map extra_info (fun i -> Option.is_some i.method_info)) = Some true in
1623 simplify_subtype_params
1624 ~is_method
1625 ~check_params_reactivity:(should_check_fun_params_reactivity ft_super)
1626 ~check_params_mutability
1627 ft_super.ft_params ft_sub.ft_params variadic_subtype variadic_supertype
1628 end &&&
1630 (* Finally do covariant subtryping on return type *)
1631 if check_return
1632 then simplify_subtype ft_sub.ft_ret ft_super.ft_ret
1633 else valid
1635 (* One of the main entry points to this module *)
1636 and sub_type
1637 (env : Env.env)
1638 (ty_sub : locl ty)
1639 (ty_super : locl ty) : Env.env =
1640 sub_type_inner env ~this_ty:None ty_sub ty_super
1642 (* Add a new upper bound ty on var. Apply transitivity of sutyping,
1643 * so if we already have tyl <: var, then check that for each ty_sub
1644 * in tyl we have ty_sub <: ty.
1646 and add_tyvar_upper_bound env r var ty =
1647 Typing_log.(log_with_level env "prop" 2 (fun () ->
1648 log_types (Reason.to_pos r) env
1649 [Log_head ("Typing_subtype.props_to_env/add_tyvar_upper_bound",
1650 [Log_type ("var", (r, Tvar var)); Log_type ("ty", ty)])]));
1651 let upper_bounds_before = Env.get_tyvar_upper_bounds env var in
1652 let env = Env.add_tyvar_upper_bound ~intersect:(try_intersect env) env var ty in
1653 let upper_bounds_after = Env.get_tyvar_upper_bounds env var in
1654 let added_upper_bounds = Typing_set.diff upper_bounds_after upper_bounds_before in
1655 let lower_bounds = Env.get_tyvar_lower_bounds env var in
1656 let env =
1657 Typing_set.fold (fun upper_bound env ->
1658 let env = Typing_subtype_tconst.make_all_type_consts_equal env var
1659 upper_bound ~as_tyvar_with_cnstr:true in
1660 Typing_set.fold (fun lower_bound env ->
1661 sub_type env lower_bound upper_bound)
1662 lower_bounds env)
1663 added_upper_bounds env in
1664 if not (Typing_set.is_empty added_upper_bounds) then
1665 Env.remove_equivalent_tyvars env var else env
1667 (* Add a new lower bound ty on var. Apply transitivity of sutyping,
1668 * so if we already have var <: tyl, then check that for each ty_super
1669 * in tyl we have ty <: ty_super.
1671 and add_tyvar_lower_bound env r var ty =
1672 Typing_log.(log_with_level env "prop" 2 (fun () ->
1673 log_types (Reason.to_pos r) env
1674 [Log_head ("Typing_subtype.props_to_env/add_tyvar_lower_bound",
1675 [Log_type ("var", (r, Tvar var)); Log_type ("ty", ty)])]));
1676 let lower_bounds_before = Env.get_tyvar_lower_bounds env var in
1677 let env = Env.add_tyvar_lower_bound ~union:(try_union env) env var ty in
1678 let lower_bounds_after = Env.get_tyvar_lower_bounds env var in
1679 let added_lower_bounds = Typing_set.diff lower_bounds_after lower_bounds_before in
1680 let upper_bounds = Env.get_tyvar_upper_bounds env var in
1681 let env =
1682 Typing_set.fold (fun lower_bound env ->
1683 let env = Typing_subtype_tconst.make_all_type_consts_equal env var
1684 lower_bound ~as_tyvar_with_cnstr:false in
1685 Typing_set.fold (fun upper_bound env ->
1686 sub_type env lower_bound upper_bound)
1687 upper_bounds env)
1688 added_lower_bounds env in
1689 if not (Typing_set.is_empty added_lower_bounds) then
1690 Env.remove_equivalent_tyvars env var else env
1692 and props_to_env env remain props =
1693 match props with
1694 | [] ->
1695 env, List.rev remain
1696 | TL.IsSubtype (((r_sub, Tvar var_sub) as ty_sub), ((r_super, Tvar var_super) as ty_super)) :: props ->
1697 let env = add_tyvar_upper_bound env r_sub var_sub ty_super in
1698 let env = add_tyvar_lower_bound env r_super var_super ty_sub in
1699 props_to_env env remain props
1700 | TL.IsSubtype ((r, Tvar var), ty) :: props ->
1701 let env = add_tyvar_upper_bound env r var ty in
1702 props_to_env env remain props
1703 | TL.IsSubtype (ty, (r, Tvar var)) :: props ->
1704 let env = add_tyvar_lower_bound env r var ty in
1705 props_to_env env remain props
1706 | TL.Conj props' :: props ->
1707 props_to_env env remain (props' @ props)
1708 | TL.Disj disj_props :: conj_props ->
1709 (* For now, just find the first prop in the disjunction that works *)
1710 let rec try_disj disj_props =
1711 match disj_props with
1712 | [] ->
1713 (* For now let it fail later when calling
1714 process_simplify_subtype_result on the remaining constraints. *)
1715 props_to_env env (TL.Disj [] :: remain) conj_props
1716 | prop :: disj_props' ->
1717 Errors.try_
1718 (fun () -> props_to_env env remain (prop::conj_props))
1719 (fun _ -> try_disj disj_props')
1721 try_disj disj_props
1722 | prop :: props ->
1723 props_to_env env (prop::remain) props
1725 (* Move any top-level conjuncts of the form Tvar v <: t or t <: Tvar v to
1726 * the type variable environment. To do: use intersection and union to
1727 * simplify bounds.
1729 and prop_to_env env prop =
1730 let env, props' = props_to_env env [] [prop] in
1731 env, TL.conj_list props'
1733 and env_to_prop env =
1734 TL.conj (tvenv_to_prop env.Env.tvenv) env.Env.subtype_prop
1736 and tvenv_to_prop tvenv =
1737 let props_per_tvar = IMap.mapi (
1738 fun id { Env.lower_bounds; Env.upper_bounds; _ } ->
1739 let tyvar = (Reason.Rnone, Tvar id) in
1740 let lower_bounds = TySet.elements lower_bounds in
1741 let upper_bounds = TySet.elements upper_bounds in
1742 let lower_bounds_props = List.map ~f:(fun ty -> TL.IsSubtype (ty, tyvar))
1743 lower_bounds in
1744 (* If an upper bound of variable n1 is a `Tvar n2`,
1745 then we have already added "Tvar n1 <: Tvar n2" when traversing
1746 lower bounds of n2, so we can filter out upper bounds that are Tvars. *)
1747 let can_be_removed = function
1748 | _, Tvar n ->
1749 begin match IMap.find_opt n tvenv with
1750 | Some _ -> true
1751 | None -> false
1753 | _ -> false in
1754 let upper_bounds = List.filter ~f:(fun ty -> not (can_be_removed ty))
1755 upper_bounds in
1756 let upper_bounds_props = List.map ~f:(fun ty -> TL.IsSubtype (tyvar, ty))
1757 upper_bounds in
1758 TL.conj_list (lower_bounds_props @ upper_bounds_props))
1759 tvenv in
1760 let _ids, props = List.unzip (IMap.bindings props_per_tvar) in
1761 TL.conj_list props
1763 and sub_type_inner
1764 (env : Env.env)
1765 ~(this_ty : locl ty option)
1766 (ty_sub: locl ty)
1767 (ty_super: locl ty) : Env.env =
1768 log_subtype ~this_ty "sub_type_inner" env ty_sub ty_super;
1769 let new_inference = TypecheckerOptions.new_inference (Env.get_tcopt env) in
1770 let env, prop = simplify_subtype
1771 ~seen_generic_params:empty_seen
1772 ~deep:new_inference
1773 ~no_top_bottom:false
1774 ~this_ty ty_sub ty_super env in
1775 let env, prop = if new_inference then prop_to_env env prop else env, prop in
1776 let env =
1777 if new_inference || TypecheckerOptions.experimental_feature_enabled
1778 (Env.get_tcopt env)
1779 TypecheckerOptions.experimental_track_subtype_prop
1780 then begin
1781 Typing_log.log_prop 2 env.Env.pos "sub_type_inner: add_subtype_prop" env prop;
1782 Env.add_subtype_prop env prop
1784 else env in
1785 let fail () = TUtils.uerror env (fst ty_super) (snd ty_super) (fst ty_sub) (snd ty_sub) in
1786 process_simplify_subtype_result ~this_ty ~fail env prop
1788 (* Deal with the cases not dealt with by simplify_subtype *)
1789 and sub_type_inner_helper env ~this_ty
1790 ty_sub ty_super =
1791 let env, ety_super =
1792 Env.expand_type env ty_super in
1793 let env, ety_sub =
1794 Env.expand_type env ty_sub in
1795 (* Default error *)
1797 let _fail () =
1798 TUtils.uerror env (fst ety_super) (snd ety_super) (fst ety_sub) (snd ety_sub);
1799 env in
1801 log_subtype ~this_ty "sub_type_inner_helper" env ty_sub ty_super;
1803 match ety_sub, ety_super with
1805 | (_, Tunresolved _), _
1806 when TypecheckerOptions.new_inference (Env.get_tcopt env) ->
1807 assert false
1809 | (_, Tunresolved _), (_, Tunresolved _) ->
1810 fst (Unify.unify env ty_super ty_sub)
1812 (****************************************************************************)
1813 (* ### Begin Tunresolved madness ###
1814 * If the supertype is a
1815 * Tunresolved, we allow it to keep growing, which is the desired behavior for
1816 * e.g. figuring out the type of a generic, but if the subtype is a
1817 * Tunresolved, then we check that all the members are indeed subtypes of the
1818 * given supertype, which is the desired behavior for e.g. checking function
1819 * return values. In general, if a supertype is Tunresolved, then we
1820 * consider it to be "not yet finalized", but if a subtype is Tunresolved
1821 * and the supertype isn't, we've probably hit a type annotation
1822 * and should consider the supertype to be definitive.
1824 * However, sometimes we want this behavior reversed, e.g. when the type
1825 * annotation has a contravariant generic parameter or a `super` constraint --
1826 * now the definitive type is the subtype.
1828 * I considered splitting this out into a separate function and swapping the
1829 * order of the super / sub types passed to it, so we would only have to handle
1830 * one set of cases, but it doesn't look much better since that function still
1831 * has to recursively call sub_type and therefore needs to remember whether its
1832 * arguments had been swapped.
1834 (****************************************************************************)
1835 | (r_sub, _), (_, Tunresolved _) ->
1836 let ty_sub = (r_sub, Tunresolved [ty_sub]) in
1837 sub_type_inner env ~this_ty ty_sub ty_super
1838 (* This case is for when Tany comes from expanding an empty Tvar - it will
1839 * result in binding the type variable to the other type. *)
1840 | _, (_, Tany) ->
1841 fst (Unify.unify env ty_super ty_sub)
1843 (* If the subtype is a type variable bound to an empty unresolved, record
1844 * this in the todo list to be checked later. But make sure that we wrap
1845 * any error using the position and reason information that was supplied
1846 * at the entry point to subtyping.
1848 | (_, Tunresolved []), _
1849 when not (TypecheckerOptions.new_inference (Env.get_tcopt env)) ->
1850 begin match ty_sub with
1851 | (_, Tvar _) ->
1852 if not
1853 (TypecheckerOptions.experimental_feature_enabled
1854 (Env.get_tcopt env)
1855 TypecheckerOptions.experimental_unresolved_fix)
1856 then env
1857 else
1858 let outer_pos = env.Env.outer_pos in
1859 let outer_reason = env.Env.outer_reason in
1860 log_subtype ~this_ty:None "add_todo" env ty_sub ty_super;
1861 Env.add_todo env begin fun env' ->
1862 Errors.try_add_err outer_pos (Reason.string_of_ureason outer_reason)
1863 (fun () ->
1864 sub_type env' ty_sub ty_super, false)
1865 (fun _ ->
1866 env', true (* Remove from todo list if there was an error *)
1870 | _ ->
1874 | (_, Tunresolved tyl), _ ->
1875 let env =
1876 List.fold_left tyl ~f:begin fun env x ->
1877 sub_type_inner env ~this_ty
1878 x ty_super
1879 end ~init:env in
1882 (****************************************************************************)
1883 (* ### End Tunresolved madness ### *)
1884 (****************************************************************************)
1886 | _, _ ->
1887 (* TODO: replace this by fail() once we support all subtyping rules that
1888 * are implemented in unification *)
1889 fst (Unify.unify env ty_super ty_sub)
1891 (* BEWARE: hack upon hack here.
1892 * To implement a predicate that tests whether `ty_sub` is a subtype of
1893 * `ty_super`, we call sub_type but handle any unification errors and
1894 * turn them into `false` result. Unfortunately HH_FIXME might end up
1895 * hiding the "error", and so we need to disable the fixme mechanism
1896 * before calling sub_type and then re-enable it afterwards.
1898 and is_sub_type
1899 (env : Env.env)
1900 (ty_sub : locl ty)
1901 (ty_super : locl ty) : bool =
1902 (* quick short circuit to help perf *)
1903 ty_equal ty_sub ty_super ||
1904 begin
1905 let f = !Errors.is_hh_fixme in
1906 Errors.is_hh_fixme := (fun _ _ -> false);
1907 let result =
1908 Errors.try_
1909 (fun () -> ignore(sub_type env ty_sub ty_super); true)
1910 (fun _ -> false) in
1911 Errors.is_hh_fixme := f;
1912 result
1915 and is_sub_type_alt env ~no_top_bottom ty1 ty2 =
1916 let _env, prop =
1917 simplify_subtype ~seen_generic_params:None ~deep:true ~no_top_bottom
1918 ~this_ty:(Some ty1) ty1 ty2 env in
1919 if TL.is_valid prop then Some true
1920 else
1921 if TL.is_unsat prop then Some false
1922 else None
1924 (* Attempt to compute the intersection of a type with an existing list intersection.
1925 * If try_intersect env t [t1;...;tn] = [u1; ...; um]
1926 * then u1&...&um must be the greatest lower bound of t and t1&...&tn wrt subtyping.
1927 * For example:
1928 * try_intersect nonnull [?C] = [C]
1929 * try_intersect t1 [t2] = [t1] if t1 <: t2
1930 * Note: it's acceptable to return [t;t1;...;tn] but the intention is that
1931 * we simplify (as above) wherever practical.
1932 * It can be assumed that the original list contains no redundancy.
1934 and try_intersect env ty tyl =
1935 let is_sub_type_alt = is_sub_type_alt ~no_top_bottom:true in
1936 match tyl with
1937 | [] -> [ty]
1938 | ty'::tyl' ->
1939 if is_sub_type_alt env ty ty' = Some true
1940 then try_intersect env ty tyl'
1941 else
1942 if is_sub_type_alt env ty' ty = Some true
1943 then tyl
1944 else
1945 let nonnull_ty = (fst ty, Tnonnull) in
1946 match ty, ty' with
1947 | (_, Toption t), _ when is_sub_type_alt env ty' nonnull_ty = Some true ->
1948 try_intersect env t (ty'::tyl')
1949 | _, (_, Toption t) when is_sub_type_alt env ty nonnull_ty = Some true ->
1950 try_intersect env t (ty::tyl')
1951 | _, _ -> ty' :: try_intersect env ty tyl'
1953 (* Attempt to compute the union of a type with an existing list union.
1954 * If try_union env t [t1;...;tn] = [u1;...;um]
1955 * then u1|...|um must be the least upper bound of t and t1|...|tn wrt subtyping.
1956 * For example:
1957 * try_union int [float] = [num]
1958 * try_union t1 [t2] = [t1] if t2 <: t1
1960 * Notes:
1961 * 1. It's acceptable to return [t;t1;...;tn] but the intention is that
1962 * we simplify (as above) wherever practical.
1963 * 2. Do not use Tunresolved for a syntactic union - the caller can do that.
1964 * 3. It can be assumed that the original list contains no redundancy.
1965 * TODO: there are many more unions to implement yet.
1967 and try_union env ty tyl =
1968 let is_sub_type_alt = is_sub_type_alt ~no_top_bottom:true in
1969 match tyl with
1970 | [] -> [ty]
1971 | ty'::tyl' ->
1972 if is_sub_type_alt env ty ty' = Some true
1973 then tyl
1974 else
1975 if is_sub_type_alt env ty' ty = Some true
1976 then try_union env ty tyl'
1977 else match snd ty, snd ty' with
1978 | Tprim Nast.Tfloat, Tprim Nast.Tint
1979 | Tprim Nast.Tint, Tprim Nast.Tfloat ->
1980 let t = MakeType.num (fst ty) in
1981 try_union env t tyl'
1982 | _, _ -> ty' :: try_union env ty tyl'
1984 let rec sub_string
1985 ?(allow_mixed = false)
1986 (p : Pos.Map.key)
1987 (env : Env.env)
1988 (ty2 : locl ty) : Env.env =
1989 let stringish_deprecated =
1990 TypecheckerOptions.disallow_stringish_magic (Env.get_tcopt env) in
1991 (* Under constraint-based inference, we implement sub_string as a subtype test.
1992 * All the cases in the legacy implementation just fall out from subtyping rules.
1993 * We test against ?(arraykey | bool | float | resource | object | dynamic)
1995 if not allow_mixed && TypecheckerOptions.new_inference (Env.get_tcopt env)
1996 then
1997 let r = Reason.Rwitness p in
1998 let tyl = [MakeType.arraykey r;
1999 MakeType.bool r;
2000 MakeType.float r;
2001 MakeType.resource r;
2002 MakeType.dynamic r] in
2003 let tyl =
2004 if stringish_deprecated
2005 then tyl
2006 else (Reason.Rwitness p, Tclass((p, SN.Classes.cStringish), Nonexact, []))::tyl in
2007 let stringish = (Reason.Rwitness p, Toption (Reason.Rwitness p, Tunresolved tyl)) in
2008 sub_type env ty2 stringish
2009 else
2010 let sub_string = sub_string ~allow_mixed in
2011 let env, ety2 = Env.expand_type env ty2 in
2012 let fail () =
2013 TUtils.uerror env (Reason.Rwitness p) (Tprim Nast.Tstring) (fst ety2) (snd ety2);
2014 env in
2016 match ety2 with
2017 | (_, Toption ty2) -> sub_string p env ty2
2018 | (_, Tunresolved tyl) ->
2019 List.fold_left tyl ~f:(sub_string p) ~init:env
2020 | (_, Tprim _) ->
2022 | (_, Tabstract (AKenum _, _)) ->
2023 (* Enums are either ints or strings, and so can always be used in a
2024 * stringish context *)
2026 | (_, Tabstract _) ->
2027 begin match TUtils.get_concrete_supertypes env ty2 with
2028 | _, [] when allow_mixed ->
2030 | _, [] ->
2031 fail ()
2032 | env, tyl ->
2033 List.fold_left tyl ~f:(sub_string p) ~init:env
2035 | (r2, Tclass (x, _, _)) ->
2036 let class_ = Env.get_class env (snd x) in
2037 (match class_ with
2038 | None -> env
2039 | Some tc
2040 (* A Stringish is a string or an object with a __toString method
2041 * that will be converted to a string *)
2042 when Cls.name tc = SN.Classes.cStringish
2043 || Cls.has_ancestor tc SN.Classes.cStringish ->
2044 if stringish_deprecated
2045 then Errors.object_string_deprecated p;
2047 | Some _ ->
2048 Errors.object_string p (Reason.to_pos r2);
2051 | _, (Tany | Terr | Tdynamic) ->
2052 env (* Tany, Terr and Tdynamic are considered Stringish by default *)
2053 | _, Tobject -> env
2054 | _, Tnonnull when allow_mixed ->
2056 | _, (Tnonnull | Tarraykind _ | Tvar _
2057 | Ttuple _ | Tanon (_, _) | Tfun _ | Tshape _) ->
2058 fail ()
2060 (** Check that the method with signature ft_sub can be used to override
2061 * (is a subtype of) method with signature ft_super.
2063 * This goes beyond subtyping on function types because methods can have
2064 * generic parameters with bounds, and `where` constraints.
2066 * Suppose ft_super is of the form
2067 * <T1 csuper1, ..., Tn csupern>(tsuper1, ..., tsuperm) : tsuper where wsuper
2068 * and ft_sub is of the form
2069 * <T1 csub1, ..., Tn csubn>(tsub1, ..., tsubm) : tsub where wsub
2070 * where csuperX and csubX are constraints on type parameters and wsuper and
2071 * wsub are 'where' constraints. Note that all types in the superclass,
2072 * including constraints (so csuperX, tsuperX, tsuper and wsuper) have had
2073 * any class type parameters instantiated appropriately according to
2074 * the actual arguments of the superclass. For example, suppose we have
2076 * class Super<T> {
2077 * function foo<Tu as A<T>>(T $x) : B<T> where T super C<T>
2079 * class Sub extends Super<D> {
2080 * ...override of foo...
2082 * then the actual signature in the superclass that we need to check is
2083 * function foo<Tu as A<D>>(D $x) : B<D> where D super C<D>
2084 * Note in particular the general form of the 'where' constraint.
2086 * (Currently, this instantiation happens in
2087 * Typing_extends.check_class_implements which in turn calls
2088 * Decl_instantiate.instantiate_ce)
2090 * Then for ft_sub to be a subtype of ft_super it must be the case that
2091 * (1) tsuper1 <: tsub1, ..., tsupern <: tsubn (under constraints
2092 * T1 csuper1, ..., Tn csupern and wsuper).
2094 * This is contravariant subtyping on parameter types.
2096 * (2) tsub <: tsuper (under constraints T1 csuper1, ..., Tn csupern and wsuper)
2097 * This is covariant subtyping on result type. For constraints consider
2098 * e.g. consider ft_super = <T super I>(): T
2099 * and ft_sub = <T>(): I
2101 * (3) The constraints for ft_super entail the constraints for ft_sub, because
2102 * we might be calling the function having checked that csuperX are
2103 * satisfied but the definition of the function (e.g. consider an override)
2104 * has been checked under csubX.
2105 * More precisely, we must assume constraints T1 csuper1, ..., Tn csupern
2106 * and wsuper, and check that T1 satisfies csub1, ..., Tn satisfies csubn
2107 * and that wsub holds under those assumptions.
2109 let subtype_method
2110 ~(check_return : bool)
2111 ~(extra_info: reactivity_extra_info)
2112 (env : Env.env)
2113 (r_sub : Reason.t)
2114 (ft_sub : decl fun_type)
2115 (r_super : Reason.t)
2116 (ft_super : decl fun_type) : Env.env =
2117 if not ft_super.ft_abstract && ft_sub.ft_abstract then
2118 (* It is valid for abstract class to extend a concrete class, but it cannot
2119 * redefine already concrete members as abstract.
2120 * See override_abstract_concrete.php test case for example. *)
2121 Errors.abstract_concrete_override ft_sub.ft_pos ft_super.ft_pos `method_;
2122 let ety_env =
2123 Phase.env_with_self env in
2124 let env, ft_super_no_tvars =
2125 Phase.localize_ft ~use_pos:ft_super.ft_pos ~ety_env ~instantiate_tparams:false env ft_super in
2126 let env, ft_sub_no_tvars =
2127 Phase.localize_ft ~use_pos:ft_sub.ft_pos ~ety_env ~instantiate_tparams:false env ft_sub in
2128 let old_tpenv = env.Env.lenv.Env.tpenv in
2130 (* We check constraint entailment and contravariant parameter/covariant result
2131 * subtyping in the context of the ft_super constraints. But we'd better
2132 * restore tpenv afterwards *)
2133 let add_tparams_constraints env (tparams: locl tparam list) =
2134 let add_bound env { tp_name = (pos, name); tp_constraints = cstrl; _ } =
2135 List.fold_left cstrl ~init:env ~f:(fun env (ck, ty) ->
2136 let tparam_ty = (Reason.Rwitness pos,
2137 Tabstract(AKgeneric name, None)) in
2138 Typing_utils.add_constraint pos env ck tparam_ty ty) in
2139 List.fold_left tparams ~f:add_bound ~init: env in
2141 let p_sub = Reason.to_pos r_sub in
2143 let add_where_constraints env (cstrl: locl where_constraint list) =
2144 List.fold_left cstrl ~init:env ~f:(fun env (ty1, ck, ty2) ->
2145 Typing_utils.add_constraint p_sub env ck ty1 ty2) in
2147 let env =
2148 add_tparams_constraints env (fst ft_super_no_tvars.ft_tparams) in
2149 let env =
2150 add_where_constraints env ft_super_no_tvars.ft_where_constraints in
2152 let env, res =
2153 simplify_subtype_funs
2154 ~seen_generic_params:empty_seen
2155 ~deep:true
2156 ~no_top_bottom:false
2157 ~check_return
2158 ~extra_info
2159 r_sub ft_sub_no_tvars
2160 r_super ft_super_no_tvars
2161 env in
2162 let env =
2163 process_simplify_subtype_result ~this_ty:None
2164 ~fail:(fun () -> ()) env res in
2166 (* This is (3) above *)
2167 let check_tparams_constraints env tparams =
2168 let check_tparam_constraints env { tp_name = (p, name); tp_constraints = cstrl; _ } =
2169 List.fold_left cstrl ~init:env ~f:begin fun env (ck, cstr_ty) ->
2170 let tgeneric = (Reason.Rwitness p, Tabstract (AKgeneric name, None)) in
2171 Typing_generic_constraint.check_constraint env ck tgeneric ~cstr_ty
2172 end in
2173 List.fold_left tparams ~init:env ~f:check_tparam_constraints in
2175 let check_where_constraints env cstrl =
2176 List.fold_left cstrl ~init:env ~f:begin fun env (ty1, ck, ty2) ->
2177 Typing_generic_constraint.check_constraint env ck ty1 ~cstr_ty:ty2
2178 end in
2180 (* We only do this if the ft_tparam lengths match. Currently we don't even
2181 * report this as an error, indeed different names for type parameters.
2182 * TODO: make it an error to override with wrong number of type parameters
2184 let env =
2185 if List.length (fst ft_sub.ft_tparams) <> List.length (fst ft_super.ft_tparams)
2186 then env
2187 else check_tparams_constraints env (fst ft_sub_no_tvars.ft_tparams) in
2188 let env =
2189 check_where_constraints env ft_sub_no_tvars.ft_where_constraints in
2191 Env.env_with_tpenv env old_tpenv
2193 let decompose_subtype_add_bound
2194 (env : Env.env)
2195 (ty_sub : locl ty)
2196 (ty_super : locl ty)
2197 : Env.env =
2198 let env, ty_super = Env.expand_type env ty_super in
2199 let env, ty_sub = Env.expand_type env ty_sub in
2200 match ty_sub, ty_super with
2201 (* name_sub <: ty_super so add an upper bound on name_sub *)
2202 | (_, Tabstract (AKgeneric name_sub, _)), _ when not (phys_equal ty_sub ty_super) ->
2203 log_subtype ~this_ty:None "decompose_subtype_add_bound" env ty_sub ty_super;
2204 let tys = Env.get_upper_bounds env name_sub in
2205 (* Don't add the same type twice! *)
2206 if Typing_set.mem ty_super tys then env
2207 else Env.add_upper_bound ~intersect:(try_intersect env) env name_sub ty_super
2209 (* ty_sub <: name_super so add a lower bound on name_super *)
2210 | _, (_, Tabstract (AKgeneric name_super, _)) when not (phys_equal ty_sub ty_super) ->
2211 log_subtype ~this_ty:None "decompose_subtype_add_bound" env ty_sub ty_super;
2212 let tys = Env.get_lower_bounds env name_super in
2213 (* Don't add the same type twice! *)
2214 if Typing_set.mem ty_sub tys then env
2215 else Env.add_lower_bound ~union:(try_union env) env name_super ty_sub
2217 | _, _ ->
2220 (* Given two types that we know are in a subtype relationship
2221 * ty_sub <: ty_super
2222 * add to env.tpenv any bounds on generic type parameters that must
2223 * hold for ty_sub <: ty_super to be valid.
2225 * For example, suppose we know Cov<T> <: Cov<D> for a covariant class Cov.
2226 * Then it must be the case that T <: D so we add an upper bound D to the
2227 * bounds for T.
2229 * Although some of this code is similar to that for sub_type_inner, its
2230 * purpose is different. sub_type_inner takes two types t and u and makes
2231 * updates to the substitution of type variables (through unification) to
2232 * make t <: u true.
2234 * decompose_subtype takes two types t and u for which t <: u is *assumed* to
2235 * hold, and makes updates to bounds on generic parameters that *necessarily*
2236 * hold in order for t <: u.
2238 let rec decompose_subtype
2240 (env : Env.env)
2241 (ty_sub : locl ty)
2242 (ty_super : locl ty)
2243 : Env.env =
2244 log_subtype ~this_ty:None "decompose_subtype" env ty_sub ty_super;
2245 let env, prop =
2246 simplify_subtype ~seen_generic_params:None
2247 ~deep:true ~no_top_bottom:false ~this_ty:None ty_sub ty_super env in
2248 decompose_subtype_add_prop p env prop
2250 and decompose_subtype_add_prop p env prop =
2251 match prop with
2252 | TL.Conj props ->
2253 List.fold_left ~f:(decompose_subtype_add_prop p) ~init:env props
2254 | TL.Disj _props ->
2255 Typing_log.log_prop 2 env.Env.pos "decompose_subtype_add_prop" env prop;
2257 | TL.Unsat _ ->
2259 | TL.IsSubtype (ty1, ty2) ->
2260 decompose_subtype_add_bound env ty1 ty2
2261 | TL.IsEqual (ty1, ty2) ->
2262 let env = decompose_subtype_add_bound env ty1 ty2 in
2263 decompose_subtype_add_bound env ty2 ty1
2265 (* Decompose a general constraint *)
2266 and decompose_constraint
2268 (env : Env.env)
2269 (ck : Ast.constraint_kind)
2270 (ty_sub : locl ty)
2271 (ty_super : locl ty)
2272 : Env.env =
2273 match ck with
2274 | Ast.Constraint_as ->
2275 decompose_subtype p env ty_sub ty_super
2276 | Ast.Constraint_super ->
2277 decompose_subtype p env ty_super ty_sub
2278 | Ast.Constraint_eq ->
2279 let env' = decompose_subtype p env ty_sub ty_super in
2280 decompose_subtype p env' ty_super ty_sub
2282 (* Given a constraint ty1 ck ty2 where ck is AS, SUPER or =,
2283 * add bounds to type parameters in the environment that necessarily
2284 * must hold in order for ty1 ck ty2.
2286 * First, we invoke decompose_constraint to add initial bounds to
2287 * the environment. Then we iterate, decomposing constraints that
2288 * arise through transitivity across bounds.
2290 * For example, suppose that env already contains
2291 * C<T1> <: T2
2292 * for some covariant class C. Now suppose we add the
2293 * constraint "T2 as C<T3>" i.e. we end up with
2294 * C<T1> <: T2 <: C<T3>
2295 * Then by transitivity we know that T1 <: T3 so we add this to the
2296 * environment too.
2298 * We repeat this process until no further bounds are added to the
2299 * environment, or some limit is reached. (It's possible to construct
2300 * types that expand forever under inheritance.)
2302 let constraint_iteration_limit = 20
2303 let add_constraint
2305 (env : Env.env)
2306 (ck : Ast.constraint_kind)
2307 (ty_sub : locl ty)
2308 (ty_super : locl ty): Env.env =
2309 log_subtype ~this_ty:None "add_constraint" env ty_sub ty_super;
2310 let oldsize = Env.get_tpenv_size env in
2311 let env' = decompose_constraint p env ck ty_sub ty_super in
2312 if Env.get_tpenv_size env' = oldsize
2313 then env'
2314 else
2315 let rec iter n env =
2316 if n > constraint_iteration_limit then env
2317 else
2318 let oldsize = Env.get_tpenv_size env in
2319 let env' =
2320 List.fold_left (Env.get_generic_parameters env) ~init:env
2321 ~f:(fun env x ->
2322 List.fold_left (Typing_set.elements (Env.get_lower_bounds env x)) ~init:env
2323 ~f:(fun env ty_sub' ->
2324 List.fold_left (Typing_set.elements (Env.get_upper_bounds env x)) ~init:env
2325 ~f:(fun env ty_super' ->
2326 decompose_subtype p env ty_sub' ty_super'))) in
2327 if Env.get_tpenv_size env' = oldsize
2328 then env'
2329 else iter (n+1) env'
2331 iter 0 env'
2333 (* Given a type ty, replace any covariant or contravariant components of the type
2334 * with fresh type variables. Components replaced include
2335 * covariant key and element types for tuples, arrays, and shapes
2336 * covariant return type and contravariant parameter types for function types
2337 * co- and contra-variant parameters to classish types and newtypes
2338 * Assert that the component is a subtype of the fresh variable (covariant) or
2339 * a supertype of the fresh variable (contravariant).
2341 * Note that the variance of type variables is set explicitly to be invariant
2342 * because we only use this function on the lower bounds of an invariant
2343 * type variable.
2345 * Also note that freshening lifts through unions and nullables.
2347 * Example 1: the type
2348 * ?dict<t1,t2>
2349 * will be transformed to
2350 * ?dict<tvar1,tvar2> with t1 <: tvar1 and t2 <: tvar2
2352 * Example 2: the type
2353 * Contra<t>
2354 * will be transformed to
2355 * Contra<tvar1> with tvar1 <: t
2357 let rec freshen_inside_ty_wrt_variance env ((r, ty_) as ty) =
2358 let default () = env, ty in
2359 match ty_ with
2360 | Tany | Tnonnull | Terr | Tdynamic | Tobject | Tprim _ | Tanon _ | Tabstract(_, None) ->
2361 default ()
2362 (* Nullable is covariant *)
2363 | Toption ty ->
2364 let env, ty = freshen_inside_ty_wrt_variance env ty in
2365 env, (r, Toption ty)
2366 | Tunresolved tyl ->
2367 let env, tyl = List.map_env env tyl freshen_inside_ty_wrt_variance in
2368 env, (r, Tunresolved tyl)
2369 (* Tuples are covariant *)
2370 | Ttuple tyl ->
2371 let env, tyl = List.map_env env tyl (freshen_ty ~variance:Ast.Covariant) in
2372 env, (r, Ttuple tyl)
2373 (* Shape data is covariant *)
2374 | Tshape (known, fdm) ->
2375 let env, fdm = ShapeFieldMap.map_env (freshen_ty ~variance:Ast.Covariant) env fdm in
2376 env, (r, Tshape (known, fdm))
2377 (* Functions are covariant in return type, contravariant in parameter types *)
2378 | Tfun ft ->
2379 let env, ft_ret = freshen_ty ~variance:Ast.Covariant env ft.ft_ret in
2380 let env, ft_params = List.map_env env ft.ft_params
2381 (fun env p ->
2382 let env, fp_type = freshen_ty ~variance:Ast.Contravariant env p.fp_type in
2383 env, { p with fp_type = fp_type }) in
2384 env, (r, Tfun { ft with ft_ret = ft_ret; ft_params = ft_params })
2385 (* Newtype definitions carry their own variance declarations *)
2386 | Tabstract (AKnewtype (name, tyl), tyopt) ->
2387 begin match Env.get_typedef env name with
2388 | None ->
2389 default ()
2390 | Some td ->
2391 let variancel = List.map td.td_tparams (fun t -> t.tp_variance) in
2392 let env, tyl = freshen_tparams_wrt_variance env variancel tyl in
2393 env, (r, Tabstract (AKnewtype (name, tyl), tyopt))
2395 | Tabstract _ ->
2396 default ()
2397 (* Classes carry their own variance declarations *)
2398 | Tclass ((p, cid), e, tyl) ->
2399 begin match Env.get_class env cid with
2400 | None ->
2401 default ()
2402 | Some cls ->
2403 let variancel = List.map (Cls.tparams cls) (fun t -> t.tp_variance) in
2404 let env, tyl = freshen_tparams_wrt_variance env variancel tyl in
2405 env, (r, Tclass((p, cid), e, tyl))
2407 (* Arrays are covariant in key and data types *)
2408 | Tarraykind ak ->
2409 begin match ak with
2410 | AKany | AKempty -> default ()
2411 | AKvarray ty ->
2412 let env, ty = freshen_ty ~variance:Ast.Covariant env ty in
2413 env, (r, Tarraykind (AKvarray ty))
2414 | AKvec ty ->
2415 let env, ty = freshen_ty ~variance:Ast.Covariant env ty in
2416 env, (r, Tarraykind (AKvec ty))
2417 | AKvarray_or_darray ty ->
2418 let env, ty = freshen_ty ~variance:Ast.Covariant env ty in
2419 env, (r, Tarraykind (AKvarray_or_darray ty))
2420 | AKdarray (ty1, ty2) ->
2421 let env, ty1 = freshen_ty ~variance:Ast.Covariant env ty1 in
2422 let env, ty2 = freshen_ty ~variance:Ast.Covariant env ty2 in
2423 env, (r, Tarraykind (AKdarray (ty1, ty2)))
2424 | AKmap (ty1, ty2) ->
2425 let env, ty1 = freshen_ty ~variance:Ast.Covariant env ty1 in
2426 let env, ty2 = freshen_ty ~variance:Ast.Covariant env ty2 in
2427 env, (r, Tarraykind (AKmap (ty1, ty2)))
2429 | Tvar _ ->
2430 default ()
2432 and freshen_ty ~variance env ty =
2433 match variance with
2434 | Ast.Invariant -> env, ty
2435 | Ast.Covariant | Ast.Contravariant ->
2436 let v = Env.fresh () in
2437 let env = Env.add_current_tyvar env (Reason.to_pos (fst ty)) v in
2438 let env = Env.set_tyvar_appears_covariantly env v in
2439 let env = Env.set_tyvar_appears_contravariantly env v in
2440 let freshty = (fst ty, Tvar v) in
2441 let env =
2442 if variance = Ast.Covariant
2443 then sub_type env ty freshty
2444 else sub_type env freshty ty in
2445 env, freshty
2447 and freshen_tparams_wrt_variance env variancel tyl =
2448 match variancel, tyl with
2449 | [], [] ->
2450 env, []
2451 | variance::variancel, ty::tyl ->
2452 let env, tyl = freshen_tparams_wrt_variance env variancel tyl in
2453 let env, ty = freshen_ty ~variance env ty in
2454 env, ty::tyl
2455 | _ ->
2456 env, tyl
2458 let bind env r var ty =
2459 Typing_log.(log_with_level env "prop" 2 (fun () ->
2460 log_types (Reason.to_pos r) env
2461 [Log_head (Printf.sprintf "Typing_subtype.bind #%d" var,
2462 [Log_type ("ty", ty)])]));
2464 (* Update the variance *)
2465 let env = Env.update_variance_after_bind env var ty in
2467 (* Unify the variable *)
2468 let env = Typing_unify_recursive.add env var ty in
2469 (* Remove the variable from the environment *)
2470 Env.remove_tyvar env var
2472 let expand_types env tys =
2473 Typing_set.fold
2474 (fun ty (env, etys) ->
2475 let env, ety = Env.expand_type env ty in
2476 env, Typing_set.add ety etys)
2478 (env, Typing_set.empty)
2480 (* Given a set of types, expand solved type variables, and eliminate
2481 * top-level unions by folding types back into the set. Remove any use of
2482 * `null` or `?t`, instead returning a boolean if
2483 * a null type exists in the set. Finally, remove any type variable match `var`
2485 let expand_and_flatten_type_set env var tys =
2487 let rec expand_and_flatten_type_list env tys has_null res =
2488 match tys with
2489 | [] -> env, has_null, Typing_set.elements res
2490 | ty::tys ->
2491 let env, ety = Env.expand_type env ty in
2492 match ety with
2493 | _, Tunresolved tys' -> expand_and_flatten_type_list env (tys' @ tys) has_null res
2494 | _, Toption ty -> expand_and_flatten_type_list env (ty::tys) true res
2495 | _, Tprim Nast.Tnull -> expand_and_flatten_type_list env tys true res
2496 | _, Tvar var' when var=var' -> expand_and_flatten_type_list env tys has_null res
2497 | _ -> expand_and_flatten_type_list env tys has_null (Typing_set.add ety res)
2499 expand_and_flatten_type_list env (TySet.elements tys) false TySet.empty
2501 (* Solve type variable var by assigning it to the union of its lower bounds.
2502 * If freshen=true, first freshen the covariant and contravariant components of
2503 * the bounds.
2505 let bind_to_lower_bound ~freshen env r var lower_bounds =
2506 (* Construct the union of the lower bounds, normalizing null|t to ?t because
2507 * some code is still sensitive to this representation.
2508 * Note that if there are no lower bounds then we will construct the empty
2509 * type, i.e. Tunresolved [].
2510 * Also note that `var` is eliminated from the bounds, as
2511 * var | t1 | ... | tn <: var
2512 * iff t1 | ... | tn <: var
2513 * This prevents it getting picked up later during the "occurs check" and
2514 * reported as a circular type error.
2516 let env, has_null, nonnulls = expand_and_flatten_type_set env var lower_bounds in
2517 let ty =
2518 match nonnulls with
2519 | [ty] -> ty
2520 | tys -> (r, Tunresolved tys) in
2521 let ty =
2522 if not has_null
2523 then ty
2524 else (fst ty, Toption ty) in
2525 (* Freshen components of the types in the union wrt their variance.
2526 * For example, if we have
2527 * Cov<C>, Contra<D> <: v
2528 * then we actually construct the union
2529 * Cov<#1> | Contra<#2> with C <: #1 and #2 <: D
2531 let env, ty =
2532 if freshen
2533 then freshen_inside_ty_wrt_variance env ty
2534 else env, ty in
2535 (* If any of the components of the union are type variables, then remove
2536 * var from their upper bounds. Why? Because if we construct
2537 * v1 , ... , vn , t <: var
2538 * for type variables v1, ..., vn and non-type variable t
2539 * then necessarily we must have var as an upper bound on each of vi
2540 * so after binding var we end up with redundant bounds
2541 * vi <: v1 | ... | vn | t
2543 let env =
2544 List.fold_left ~f:(fun env ty ->
2545 match Env.expand_type env ty with
2546 | env, (_, Tvar v) ->
2547 Env.remove_tyvar_upper_bound env v var
2548 | env, _ -> env) ~init:env nonnulls in
2549 (* Now actually make the assignment var := ty, and remove var from tvenv *)
2550 bind env r var ty
2552 let bind_to_upper_bound env r var upper_bounds =
2553 let env, upper_bounds = expand_types env upper_bounds in
2554 match Typing_set.elements upper_bounds with
2555 | [] -> bind env r var (MakeType.mixed r)
2556 | [ty] ->
2557 (* If ty is a variable (in future, if any of the types in the list are variables),
2558 * then remove var from their lower bounds. Why? Because if we construct
2559 * var <: v1 , ... , vn , t
2560 * for type variables v1 , ... , vn and non-type variable t
2561 * then necessarily we must have var as a lower bound on each of vi
2562 * so after binding var we end up with redundant bounds
2563 * v1 & ... & vn & t <: vi
2565 let env =
2566 (match Env.expand_type env ty with
2567 | env, (_, Tvar v) ->
2568 Env.remove_tyvar_lower_bound env v var
2569 | env, _ -> env) in
2570 bind env r var ty
2571 (* For now, if there are multiple bounds, then don't solve. *)
2572 | _ -> env
2574 (* Use the variance information about a type variable to force a solution.
2575 * (1) If the type variable is bounded by t1, ..., tn <: v and it appears only
2576 * covariantly or not at all in the expression type then
2577 * we can minimize it i.e. set v := t1 | ... | tn.
2578 * (2) If the type variable is bounded by v <: t1, ..., tn and it appears only
2579 * contravariantly in the expression type then we can maximize it. Ideally we
2580 * would use an intersection v := t1 & ... & tn so for now we only solve
2581 * if there is a single upper bound.
2582 * (3) If the type variable is bounded by t1, ..., tm <: v <: u1, ..., un and
2583 * u1 & ... & un == t1 | ... | tm then we can set v to either of these
2584 * equivalent types. Because we don't have intersections, for now we check if
2585 * there exist i, j such that uj <: ti, which implies ti == uj and allows
2586 * us to set v := ti.
2588 let solve_tyvar ~freshen ~solve_invariant env r var =
2589 Typing_log.(log_with_level env "prop" 2 (fun () ->
2590 log_types (Reason.to_pos r) env
2591 [Log_head (Printf.sprintf "Typing_subtype.solve_tyvar #%d" var, [])]));
2593 (* Don't try and solve twice *)
2594 if Env.tyvar_is_solved env var
2595 then env
2596 else
2597 let tyvar_info = Env.get_tyvar_info env var in
2598 let r = if r = Reason.Rnone then Reason.Rwitness tyvar_info.Env.tyvar_pos else r in
2599 match tyvar_info.Env.appears_covariantly, tyvar_info.Env.appears_contravariantly with
2600 | true, false
2601 | false, false ->
2602 (* As in Local Type Inference by Pierce & Turner, if type variable does
2603 * not appear at all, or only appears covariantly, force to lower bound
2605 bind_to_lower_bound ~freshen:false env r var tyvar_info.Env.lower_bounds
2606 | false, true ->
2607 (* As in Local Type Inference by Pierce & Turner, if type variable
2608 * appears only contravariantly, force to upper bound
2610 bind_to_upper_bound env r var tyvar_info.Env.upper_bounds
2611 | true, true ->
2612 (* As in Local Type Inference by Pierce & Turner, if type variable
2613 * appears both covariantly and contravariantly and there is a type that
2614 * is both a lower and upper bound, force to that type
2616 let lower_bounds = tyvar_info.Env.lower_bounds in
2617 let upper_bounds = tyvar_info.Env.upper_bounds in
2618 match Typing_set.choose_opt (Typing_set.inter lower_bounds upper_bounds) with
2619 | Some ty -> bind env r var ty
2620 | None ->
2621 if solve_invariant
2622 then bind_to_lower_bound ~freshen env r var lower_bounds
2623 else env
2625 let solve_tyvars ?(solve_invariant = false) ~tyvars env =
2626 if TypecheckerOptions.new_inference (Env.get_tcopt env)
2627 then List.fold_left tyvars ~init:env
2628 ~f:(fun env tyvar -> solve_tyvar ~freshen:false ~solve_invariant env Reason.Rnone tyvar)
2629 else env
2631 (* Expand an already-solved type variable, and solve an unsolved type variable
2632 * by binding it to the union of its lower bounds, with covariant and contravariant
2633 * components of the type suitably "freshened". For example,
2634 * vec<C> <: #1
2635 * will be solved by
2636 * #1 := vec<#2> where C <: #2
2638 let expand_type_and_solve env ty =
2639 let env, ety = Env.expand_type env ty in
2640 match ety with
2641 | (r, Tvar v) when not (TypecheckerOptions.new_inference_no_eager_solve (Env.get_tcopt env)) ->
2642 let env = solve_tyvar ~freshen:true ~solve_invariant:true env r v in
2643 Env.expand_type env ty
2644 | _ ->
2645 env, ety
2647 let close_tyvars_and_solve env =
2648 let tyvars = Env.get_current_tyvars env in
2649 let env = Env.close_tyvars env in
2650 solve_tyvars ~tyvars env
2652 let log_prop env =
2653 let filename = Pos.filename (Pos.to_absolute env.Env.pos) in
2654 if Str.string_match (Str.regexp {|.*\.hhi|}) filename 0 then () else
2655 let prop = env_to_prop env in
2656 if TypecheckerOptions.log_inference_constraints (Env.get_tcopt env) then (
2657 let p_as_string = Typing_print.subtype_prop env prop in
2658 let pos = Pos.string (Pos.to_absolute env.Env.pos) in
2659 let size = TL.size prop in
2660 let n_disj = TL.n_disj prop in
2661 let n_conj = TL.n_conj prop in
2662 TypingLogger.InferenceCnstr.log p_as_string ~pos ~size ~n_disj ~n_conj);
2663 if TypecheckerOptions.new_inference (Env.get_tcopt env) &&
2664 not (Errors.currently_has_errors ()) &&
2665 not (TL.is_valid prop)
2666 then Typing_log.log_prop ~do_normalize:true 1 env.Env.pos
2667 "There are remaining unsolved constraints!" env prop
2669 (*****************************************************************************)
2670 (* Exporting *)
2671 (*****************************************************************************)
2673 let () = Typing_utils.sub_type_ref := sub_type
2674 let () = Typing_utils.add_constraint_ref := add_constraint
2675 let () = Typing_utils.is_sub_type_ref := is_sub_type
2676 let () = Typing_utils.is_sub_type_alt_ref := is_sub_type_alt
2677 let () = Typing_utils.expand_type_and_solve_ref := expand_type_and_solve