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