2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
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 = {
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
43 | Some
(_
, ((_
, x
) as sid
), _
) ->
44 begin match Env.get_class env x
with
46 | Some cls
-> Some
(sid
, cls
)
49 let try_get_method_from_condition_type
53 (method_name
: string) =
54 match try_get_class_for_condition_type env ty
with
56 let get = if is_static
then Cls.get_smethod
else Cls.get_method
in
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 *)
66 match try_get_class_for_condition_type env
ty with
68 | Some
(_
, cls
) when Cls.tparams cls
= [] -> ty
69 | Some
(((p
, _
) as sid
), cls
) ->
71 List.map
(Cls.tparams cls
)
72 ~f
:(fun { tp_name
= (p
,x
); _
} -> Reason.Rwitness p
, Tgeneric x
) in
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
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
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
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)
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
) =
125 let env, p2
= f
env in
128 let (|||) (env, p1
) (f
: Env.env -> Env.env * TL.subtype_prop
) =
132 let env, p2
= f
env in
135 let if_unsat (f
: unit -> Env.env * TL.subtype_prop
) (env, p
) =
140 (** Check that a mutability type is a subtype of another mutability type *)
144 (mut_sub
: param_mutability
option)
146 (mut_super
: param_mutability
option)
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
))
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 () ->
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)]
185 let is_final_and_not_contravariant env id
=
186 let class_def = Env.get_class
env id
in
188 | Some class_ty
-> TUtils.class_is_final_and_not_contravariant class_ty
191 (* Process the constraint proposition *)
192 let rec process_simplify_subtype_result ~this_ty ~fail
env prop
=
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
)
202 (* Evaluates list from left-to-right so preserves order of conjuncts *)
205 ~f
:(process_simplify_subtype_result ~this_ty ~fail
)
208 process_simplify_subtype_result ~this_ty ~fail
env prop
211 let rec try_disj props
=
217 Errors.try_
begin fun () ->
218 process_simplify_subtype_result ~this_ty ~fail
env prop
end
219 (fun _ -> 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)
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
237 ~
(seen_generic_params
: SSet.t
option)
238 ?
(deep
: bool = true)
239 ~
(no_top_bottom
: bool)
240 ?
(this_ty
: locl
ty option = None
)
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 *)
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
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
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 =
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
293 let r = Reason.Rimplicit_upper_bound
(Reason.to_pos
(fst ety_sub
), "?nonnull") in
294 let tmixed = MakeType.mixed
r in
296 simplify_subtype ~
seen_generic_params ~deep ~
this_ty tmixed ty_super
300 simplify_subtype ~
seen_generic_params ~deep ~
this_ty ty ty_super
305 simplify_subtype ~
seen_generic_params ~deep ~
this_ty ty ty_super
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 *)
314 let simplify_subtype_generic_super ty_sub name_super
env =
315 begin match seen_generic_params with
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
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 =
336 simplify_subtype ~
seen_generic_params ~deep ~
this_ty ty_sub
ty |||
339 (* Turn error into a generic error about the type parameter *)
341 try_bounds (Typing_set.elements
(Env.get_lower_bounds
env name_super
)) |>
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
_),
365 | (Tdynamic
| Toption
_ | Tprim
Nast.(Tnull
| Tvoid
)),
369 | Tabstract
((AKnewtype
_ | AKdependent
_), Some
ty), Tnonnull
->
370 simplify_subtype ~
seen_generic_params ~deep ~
this_ty ty ty_super
env
372 | Tdynamic
, Tdynamic
->
374 | (Tnonnull
| Toption
_ | Tprim
_ | Tfun
_ | Ttuple
_ | Tshape
_ |
375 Tabstract
(AKenum
_, _) | Tanon
_ | Tobject
| Tclass
_ | Tarraykind
_),
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
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
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
),
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 *)
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
->
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 ->
453 simplify_subtype ~
seen_generic_params ~deep ~
this_ty ty_sub arg_ty_super
|||
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
->
463 | (Tnonnull
| Tdynamic
| Tfun
_ | Ttuple
_ | Tshape
_ | Tanon
_ |
464 Tabstract
(AKenum
_, None
) | Tobject
| Tclass
_ | Tarraykind
_),
468 Tprim
Nast.(Tvoid
| Tint
| Tbool
| Tfloat
| Tstring
| Tresource
| Tnum
|
469 Tarraykey
| Tnoreturn
) ->
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
_ ->
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
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
;
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) |>
505 let env, _, ret
= anon
env ft
.ft_params ft
.ft_arity
in
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
_),
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
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
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
_),
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
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
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
(
557 TUtils.get_printable_shape_field_name name
559 res
&&& simplify_subtype ~
seen_generic_params ~deep ~
this_ty (MakeType.mixed
r) ty_super
in
562 ~
on_missing_omittable_optional_field
563 ~
on_missing_non_omittable_optional_field
564 ~on_error
:(fun _ f
-> invalid_with f
)
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
_, _) ->
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
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
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
_, _) ->
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 () ->
621 let p = Reason.to_pos
(fst ety_sub
) in
623 then Errors.exact_class_final id
p error
624 else Errors.this_final id
p error
))
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
_) ->
633 | (Tnonnull
| Tdynamic
| Toption
_ | Tprim
_ | Ttuple
_ | Tshape
_ |
634 Tabstract
(AKenum
_, _) | Tobject
| Tclass
_ | Tarraykind
_),
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
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
_),
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
->
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
662 | Tabstract
(AKenum enum_name
, Some
ty), Tclass
((_, class_name
), exact
, _) ->
663 if enum_name
= class_name
&& exact
= Nonexact
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
)
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
_),
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
) ->
682 match exact_sub
, exact_super
with
683 | Nonexact
, Exact
-> false
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
691 (* If class is final then exactness is superfluous *)
693 match class_def_sub with
694 | Some tc
-> Cls.final tc
696 if not
(exact_match || is_final)
699 (* We handle the case where a generic A<T> is used as A *)
701 if List.is_empty
tyl_super && not
(Env.is_strict
env)
702 then List.map tyl_sub
(fun _ -> (p_super, Tany
))
705 if List.is_empty
tyl_sub && not
(Env.is_strict
env)
706 then List.map
tyl_super (fun _ -> (p_super, Tany
))
708 if List.length
tyl_sub <> List.length
tyl_super
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)
716 if List.is_empty
tyl_sub && List.is_empty
tyl_super
720 match class_def_sub with
722 List.map
tyl_sub (fun _ -> Ast.Invariant
)
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
737 begin match class_def_sub with
739 (* This should have been caught already in the naming phase *)
743 (* We handle the case where a generic A<T> is used as A *)
745 if List.is_empty
tyl_sub && not
(Env.is_strict
env)
746 then List.map
(Cls.tparams class_sub
) (fun _ -> (p_sub, Tany
))
748 if List.length
(Cls.tparams class_sub
) <> List.length
tyl_sub
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
)))
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
;
763 let up_obj = Cls.get_ancestor class_sub
cid_super in
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
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
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 *)
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
782 let env, req_type
= Phase.localize ~
ety_env env req_type
in
784 simplify_subtype ~
seen_generic_params ~deep ~
this_ty
785 (p_sub, snd req_type
) ty_super
788 try_reqs (Cls.all_ancestor_reqs class_sub
) env
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
) ->
800 (* array <: Traversable<t> and emptyarray <: Traversable<t> for any t *)
802 | AKempty
-> valid ()
803 (* vec<tv> <: Traversable<tv_super>
805 * Likewise for vec<tv> <: Container<tv_super>
806 * and map<_,tv> <: Traversable<tv_super>
807 * and map<_,tv> <: Container<tv_super>
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
822 | AKempty
-> valid ()
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
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
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
845 | Ttuple
_, Tarraykind AKany
->
846 if TypecheckerOptions.disallow_array_as_tuple
(Env.get_tcopt
env)
849 | (Tnonnull
| Tdynamic
| Toption
_ | Tprim
_ | Tfun
_ | Ttuple
_ |
850 Tshape
_ | Tabstract
(AKenum
_, _) | Tanon
_ | Tobject
| Tclass
_),
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 *)
862 (* An empty array is a subtype of any array type *)
866 (* array is a subtype of varray_or_darray<_> *)
867 | AKany
, AKvarray_or_darray
(_, Tany
) ->
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
)) ->
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
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 *)
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
914 * t1 <: t /\ ... /\ tn <: t
915 * We want this even if t is a type variable e.g. consider
918 | Tunresolved tyl
, _->
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
)
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
929 | Toption t
, Tvar
_ when new_inference ->
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
_ ->
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
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.
956 let rec try_each tys
env =
963 simplify_subtype ~
seen_generic_params ~deep ~
this_ty ty_sub
ty
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
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 ->
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
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
1009 * where we have the constraint
1011 * Then it's necessary to apply the rule for AKdependent first, so we
1012 * reduce this problem to
1014 * and then call sub_generic_params to deal with the type parameter.
1015 * (2) Alternatively, suppose we again have to check
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 ->
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)
1043 ~
(no_top_bottom
: bool)
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
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
1057 | _, _, [] -> valid env
1058 | variance
:: variancel, child
:: childrenl
, super
:: superl
->
1059 begin match variance
with
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
1067 let super'
= (Reason.Rinvariant_generic
(fst
super,
1068 Utils.strip_ns cid
), snd
super) in
1072 simplify_subtype child
super'
&&&
1073 simplify_subtype super child
1075 env, TL.IsEqual
(child
, super'
)
1077 simplify_subtype_variance cid
variancel childrenl superl
1079 and simplify_subtype_params
1080 ~
(seen_generic_params : SSet.t
option)
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)
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.
1104 public function a(int $x = 0, string ... $args) // superl = [int], super_var = string
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
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
1127 | Some
ty -> simplify_supertype_params_with_variadic superl
ty env)
1128 | _, [] -> (match variadic_sub_ty
with
1130 | Some
ty -> simplify_subtype_params_with_variadic subl
ty env)
1131 | sub
:: subl
, super :: superl
->
1134 if check_params_reactivity
1135 then subtype_fun_params_reactivity sub
super
1139 if check_params_mutability
1140 then check_mutability
1142 sub
.fp_pos sub
.fp_mutability
super.fp_pos
super.fp_mutability
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. *)
1160 simplify_subtype ty_super ty_sub
&&&
1161 simplify_subtype ty_sub ty_super
1164 simplify_subtype ty_sub ty_super
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)
1172 ~
(no_top_bottom
: bool)
1173 (subl
: locl fun_param list
)
1174 (variadic_ty
: locl
ty)
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
1181 | { fp_type
= sub
; _ } :: subl
->
1182 let env = { env with Env.pos
= Reason.to_pos
(fst sub
) } in
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)
1190 ~
(no_top_bottom
: bool)
1191 (superl
: locl fun_param list
)
1192 (variadic_ty
: locl
ty)
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
1199 | { fp_type
= super; _ } :: superl
->
1200 let env = { env with Env.pos
= Reason.to_pos
(fst
super) } in
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)
1209 (r_sub : reactivity
)
1210 (r_super
: reactivity
) : bool =
1212 let maybe_localize t
=
1215 let ety_env = Phase.env_with_self
env in
1216 let _, t
= Phase.localize ~
ety_env env t
in
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
) =
1231 ConditionTypes.try_get_method_from_condition_type
1232 env condition_type_super is_static method_name
in
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
->
1243 empty_extra_info with parent_class_ty
= Some
(DeclTy condition_type_super
)
1245 subtype_reactivity ~
extra_info env f
.ft_reactive r_super
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
1268 class A { function f((function(): int) $f) {} }
1271 function f(<<__AtMostRxAsFunc>> (function(): int) $f);
1273 reactivity for arguments is checked contravariantly *)
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
->
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.
1293 public function f(): int;
1296 <<__RxIfImplements(Rx::class)>>
1297 public function f(): int { ... }
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
->
1312 (* call_site specific cases *)
1313 (* shallow can call into local *)
1314 | Local cond_sub
, Shallow cond_super
, _ when
1316 subtype_param_rx_if_impl ~is_param
:false env cond_sub
class_ty cond_super
->
1318 (* local can call into non-reactive *)
1319 | Nonreactive
, Local
_, _ when is_call_site
-> true
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
1329 (cond_type_sub
: decl
ty option)
1330 (declared_type_sub
: locl
ty option)
1331 (cond_type_super
: decl
ty option) =
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)
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 {
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:
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
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
1380 interface B extends A {}
1381 interface C extends B {}
1384 <<__Rx, __OnlyRxIfImpl(B::class)>>
1385 public function f(): void;
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
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
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
1412 public function f(int $a): void;
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 {
1422 | Some
cond_type_sub, None
->
1423 Option.value_map declared_type_sub
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
)
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
1441 function super((function(): int) $f);
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
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
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 *)
1471 | cond_sub
, cond_super
->
1474 | Some
(Param_rx_if_impl t
) -> Some t
1476 let cond_type_super =
1477 match cond_super
with
1478 | Some
(Param_rx_if_impl t
) -> Some t
1481 subtype_param_rx_if_impl ~is_param
:true env cond_type_sub (Some
p_sub.fp_type
)
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
1496 and check_subtype_funs_attributes
1497 ?
(extra_info: reactivity_extra_info
option)
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
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
))
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) |>
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 *)
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) |>
1529 (ft_super
.ft_reactive
= Nonreactive
1530 || ft_super
.ft_returns_void_to_rx
1531 || not ft_sub
.ft_returns_void_to_rx
)
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:
1538 public function f(): A { return new 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
) |>
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
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)
1586 ~
(no_top_bottom
: bool)
1587 ~
(check_return
: bool)
1588 ?
(extra_info: reactivity_extra_info
option)
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
1598 let variadic_supertype = match ft_super
.ft_arity
with
1599 | Fvariadic
(_, {fp_type
= var_super
; _ }) -> Some var_super
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 *)
1608 check_subtype_funs_attributes ?
extra_info r_sub ft_sub r_super ft_super
&&&
1610 (* Now do contravariant subtyping on parameters *)
1612 match variadic_subtype, variadic_supertype with
1613 | Some var_sub
, Some var_super
-> simplify_subtype var_super var_sub
1618 let check_params_mutability =
1619 ft_super
.ft_reactive
<> Nonreactive
&&
1620 ft_sub
.ft_reactive
<> Nonreactive
in
1622 (Option.map
extra_info (fun i
-> Option.is_some i
.method_info
)) = Some
true in
1623 simplify_subtype_params
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
1630 (* Finally do covariant subtryping on return type *)
1632 then simplify_subtype ft_sub
.ft_ret ft_super
.ft_ret
1635 (* One of the main entry points to this module *)
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
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
)
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
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
)
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
=
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
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'
->
1718 (fun () -> props_to_env
env remain
(prop
::conj_props
))
1719 (fun _ -> try_disj disj_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
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))
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
1749 begin match IMap.find_opt n tvenv
with
1754 let upper_bounds = List.filter ~f
:(fun ty -> not
(can_be_removed ty))
1756 let upper_bounds_props = List.map ~f
:(fun ty -> TL.IsSubtype
(tyvar, ty))
1758 TL.conj_list
(lower_bounds_props @ upper_bounds_props))
1760 let _ids, props
= List.unzip
(IMap.bindings
props_per_tvar) in
1765 ~
(this_ty : locl
ty option)
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
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
1777 if new_inference || TypecheckerOptions.experimental_feature_enabled
1779 TypecheckerOptions.experimental_track_subtype_prop
1781 Typing_log.log_prop
2 env.Env.pos
"sub_type_inner: add_subtype_prop" env prop
;
1782 Env.add_subtype_prop
env prop
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
1791 let env, ety_super
=
1792 Env.expand_type
env ty_super
in
1794 Env.expand_type
env ty_sub
in
1798 TUtils.uerror env (fst ety_super
) (snd ety_super
) (fst ety_sub
) (snd ety_sub
);
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) ->
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. *)
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
1853 (TypecheckerOptions.experimental_feature_enabled
1855 TypecheckerOptions.experimental_unresolved_fix
)
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)
1864 sub_type
env'
ty_sub ty_super
, false)
1866 env'
, true (* Remove from todo list if there was an error *)
1874 | (_, Tunresolved tyl
), _ ->
1876 List.fold_left tyl ~f
:begin fun env x
->
1877 sub_type_inner
env ~
this_ty
1882 (****************************************************************************)
1883 (* ### End Tunresolved madness ### *)
1884 (****************************************************************************)
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.
1901 (ty_super
: locl
ty) : bool =
1902 (* quick short circuit to help perf *)
1903 ty_equal
ty_sub ty_super
||
1905 let f = !Errors.is_hh_fixme
in
1906 Errors.is_hh_fixme
:= (fun _ _ -> false);
1909 (fun () -> ignore
(sub_type
env ty_sub ty_super
); true)
1911 Errors.is_hh_fixme
:= f;
1915 and is_sub_type_alt
env ~no_top_bottom ty1 ty2
=
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
1921 if TL.is_unsat prop
then Some
false
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.
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
1939 if is_sub_type_alt env ty ty'
= Some
true
1940 then try_intersect
env ty tyl'
1942 if is_sub_type_alt env ty'
ty = Some
true
1945 let nonnull_ty = (fst
ty, Tnonnull
) in
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.
1957 * try_union int [float] = [num]
1958 * try_union t1 [t2] = [t1] if t2 <: t1
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
1972 if is_sub_type_alt env ty ty'
= Some
true
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'
1985 ?
(allow_mixed
= false)
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)
1997 let r = Reason.Rwitness
p in
1998 let tyl = [MakeType.arraykey
r;
2001 MakeType.resource
r;
2002 MakeType.dynamic
r] in
2004 if stringish_deprecated
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
2010 let sub_string = sub_string ~allow_mixed
in
2011 let env, ety2
= Env.expand_type
env ty2
in
2013 TUtils.uerror env (Reason.Rwitness
p) (Tprim
Nast.Tstring
) (fst ety2
) (snd ety2
);
2017 | (_, Toption ty2
) -> sub_string p env ty2
2018 | (_, Tunresolved
tyl) ->
2019 List.fold_left
tyl ~
f:(sub_string p) ~init
:env
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
->
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
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;
2048 Errors.object_string
p (Reason.to_pos r2
);
2051 | _, (Tany
| Terr
| Tdynamic
) ->
2052 env (* Tany, Terr and Tdynamic are considered Stringish by default *)
2054 | _, Tnonnull
when allow_mixed
->
2056 | _, (Tnonnull
| Tarraykind
_ | Tvar
_
2057 | Ttuple
_ | Tanon
(_, _) | Tfun
_ | Tshape
_) ->
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
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.
2110 ~
(check_return
: bool)
2111 ~
(extra_info: reactivity_extra_info
)
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_
;
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
2148 add_tparams_constraints env (fst ft_super_no_tvars
.ft_tparams
) in
2150 add_where_constraints env ft_super_no_tvars
.ft_where_constraints
in
2153 simplify_subtype_funs
2154 ~
seen_generic_params:empty_seen
2156 ~no_top_bottom
:false
2159 r_sub ft_sub_no_tvars
2160 r_super ft_super_no_tvars
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
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
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
2185 if List.length
(fst ft_sub
.ft_tparams
) <> List.length
(fst ft_super
.ft_tparams
)
2187 else check_tparams_constraints env (fst ft_sub_no_tvars
.ft_tparams
) in
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
2196 (ty_super
: locl
ty)
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
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
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
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
2242 (ty_super
: locl
ty)
2244 log_subtype ~
this_ty:None
"decompose_subtype" env ty_sub ty_super
;
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
=
2253 List.fold_left ~
f:(decompose_subtype_add_prop
p) ~init
:env props
2255 Typing_log.log_prop
2 env.Env.pos
"decompose_subtype_add_prop" env prop
;
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
2269 (ck
: Ast.constraint_kind
)
2271 (ty_super
: locl
ty)
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
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
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
2306 (ck
: Ast.constraint_kind
)
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
2315 let rec iter n
env =
2316 if n
> constraint_iteration_limit then env
2318 let oldsize = Env.get_tpenv_size
env in
2320 List.fold_left
(Env.get_generic_parameters
env) ~init
:env
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
2329 else iter (n
+1) 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
2345 * Also note that freshening lifts through unions and nullables.
2347 * Example 1: the type
2349 * will be transformed to
2350 * ?dict<tvar1,tvar2> with t1 <: tvar1 and t2 <: tvar2
2352 * Example 2: the type
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
2360 | Tany
| Tnonnull
| Terr
| Tdynamic
| Tobject
| Tprim
_ | Tanon
_ | Tabstract
(_, None
) ->
2362 (* Nullable is covariant *)
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 *)
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 *)
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
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
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
))
2397 (* Classes carry their own variance declarations *)
2398 | Tclass
((p, cid
), e
, tyl) ->
2399 begin match Env.get_class
env cid
with
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 *)
2410 | AKany
| AKempty
-> default ()
2412 let env, ty = freshen_ty ~variance
:Ast.Covariant
env ty in
2413 env, (r, Tarraykind
(AKvarray
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
)))
2432 and freshen_ty ~variance
env ty =
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
2442 if variance
= Ast.Covariant
2443 then sub_type
env ty freshty
2444 else sub_type
env freshty ty in
2447 and freshen_tparams_wrt_variance
env variancel tyl =
2448 match variancel, tyl with
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
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 =
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
=
2489 | [] -> env, has_null
, Typing_set.elements res
2491 let env, ety
= Env.expand_type
env ty in
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
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
2520 | tys -> (r, Tunresolved
tys) in
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
2533 then freshen_inside_ty_wrt_variance env ty
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
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 *)
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)
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
2566 (match Env.expand_type
env ty with
2567 | env, (_, Tvar
v) ->
2568 Env.remove_tyvar_lower_bound
env v var
2571 (* For now, if there are multiple bounds, then don't solve. *)
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
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
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
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
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
2622 then bind_to_lower_bound ~freshen
env r var
lower_bounds
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)
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,
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
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
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
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 (*****************************************************************************)
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