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.
14 open Typing_dependent_type
15 module Env
= Typing_env
16 module TUtils
= Typing_utils
17 module TGenConstraint
= Typing_generic_constraint
18 module Subst
= Decl_subst
19 module MakeType
= Typing_make_type
20 module Cls
= Decl_provider.Class
22 (* Here is the general problem the delayed application of the phase solves.
23 * Let's say you have a function that you want to operate generically across
24 * phases. In most cases when you do this you can use the 'ty' GADT and locally
25 * abstract types to write code in a phase agonistic way.
27 * let yell_any: type a. a ty -> string = fun ty ->
32 * Now let's add a function that works for all phases, but whose logic is phase
33 * dependent. For this we can use 'phase_ty' ADT:
35 * let yell_locl phase_ty =
38 * | LoclTy ty -> "Locl"
40 * Let's say you want to write a function that has behavior that works across
41 * phases, but needs to invoke a function that is phase dependent. Our options
44 * let yell_any_or_locl phase_ty =
45 * let ans = yell_locl phase_ty in
47 * | DeclTy ty -> ans ^ (yell_any ty)
48 * | LoclTy ty -> ans ^ (yell_any ty)
50 * This would lead to code duplication since we can't generically operate on the
51 * underlying 'ty' GADT. If we want to eliminate this code duplication there are
54 * let generic_ty: type a. phase_ty -> a ty = function
58 * let yell_any_or_locl phase_ty =
59 * let ans = yell_locl phase_ty in
60 * ans ^ (yell_any (generic_ty phase_ty))
62 * generic_ty allows us to extract a generic value which we can use. This
63 * approach is limiting because we lose all information about what phase 'a ty
66 * The other approach is to pass in a function that goes from 'a ty -> phase_ty'
68 * let yell_any_or_locl phase ty =
69 * let ans = yell_locl (phase ty) in
72 * Here we can use 'ty' generically (without losing information about what phase
73 * 'a ty' is), and we rely on the caller passing in an appropriate function that
74 * converts into the 'phase_ty' when we need to hop into phase specific code.
76 let decl ty
= DeclTy ty
78 let locl ty
= LoclTy ty
80 type method_instantiation
= {
83 explicit_targs
: Tast.targ list
;
86 let env_with_self ?pos ?
(quiet
= false) ?report_cycle env
=
87 let this_ty = mk
(Reason.none
, TUtils.this_of
(Env.get_self env
)) in
91 match report_cycle
with
93 | Some
(pos
, id
) -> [(true, pos
, id
)]
101 | None
-> Errors.unify_error
102 | Some pos
-> Errors.unify_error_at pos
);
105 (*****************************************************************************)
106 (* Transforms a declaration phase type into a localized type. This performs
107 * common operations that are necessary for this operation, specifically:
108 * > Expand newtype/types
109 * > Resolves the "this" type
110 * > Instantiate generics
113 * When keep track of additional information while localizing a type such as
114 * what type defs were expanded to detect potentially recursive definitions..
116 (*****************************************************************************)
118 let rec localize ~ety_env env
(dty
: decl_ty
) =
119 let tvar_or_localize ~ety_env env r ty ~i
=
121 GlobalOptions.tco_global_inference env
.genv
.tcopt
122 && (is_any ty
|| is_tyvar ty
)
124 Env.new_global_tyvar env ~i r
126 localize ~ety_env env ty
129 | (r
, Terr
) -> (env
, TUtils.terr env r
)
130 | (r
, Tany _
) -> (env
, mk
(r
, TUtils.tany env
))
131 | (r
, Tvar _var
) -> Env.new_global_tyvar env r
132 | (r
, ((Tnonnull
| Tprim _
| Tdynamic
) as x
)) -> (env
, mk
(r
, x
))
133 | (r
, Tmixed
) -> (env
, MakeType.mixed r
)
136 match deref ety_env
.this_ty with
137 | (Reason.Rnone
, ty) -> mk
(r
, ty)
138 | (Reason.Rexpr_dep_type
(_
, pos
, s
), ty) ->
139 mk
(Reason.Rexpr_dep_type
(r
, pos
, s
), ty)
140 | (reason
, ty) when Option.is_some ety_env
.from_class
-> mk
(reason
, ty)
142 mk
(Reason.Rinstantiate
(reason
, SN.Typehints.this
, r
), ty)
145 match ety_env
.from_class
with
146 | Some cid
-> ExprDepTy.make env cid
ty
150 | (r
, Tarray
(ty1
, ty2
)) ->
152 match (ty1
, ty2
) with
154 let tk = MakeType.arraykey
Reason.(Rvarray_or_darray_key
(to_pos r
)) in
156 if GlobalOptions.tco_global_inference env
.genv
.tcopt
then
157 Env.new_global_tyvar env r
159 (env
, mk
(r
, TUtils.tany env
))
161 (env
, Tvarray_or_darray
(tk, tv
))
163 let (env
, tv
) = tvar_or_localize ~ety_env env r tv ~i
:1 in
165 | (Some
tk, Some tv
) ->
166 let (env
, tk) = tvar_or_localize ~ety_env env r
tk ~i
:0 in
167 let (env
, tv
) = tvar_or_localize ~ety_env env r tv ~i
:1 in
168 (env
, Tdarray
(tk, tv
))
169 | (None
, Some _
) -> failwith
"Invalid array declaration type"
172 | (r
, Tdarray
(tk, tv
)) ->
173 let (env
, tk) = tvar_or_localize ~ety_env env r
tk ~i
:0 in
174 let (env
, tv
) = tvar_or_localize ~ety_env env r tv ~i
:1 in
175 let ty = Tdarray
(tk, tv
) in
178 let (env
, tv
) = tvar_or_localize ~ety_env env r tv ~i
:0 in
179 let ty = Tvarray tv
in
181 | (r
, Tvarray_or_darray
(tk, tv
)) ->
182 let (env
, tk) = tvar_or_localize ~ety_env env r
tk ~i
:0 in
183 let (env
, tv
) = tvar_or_localize ~ety_env env r tv ~i
:1 in
184 (env
, MakeType.varray_or_darray r
tk tv
)
187 match SMap.find_opt x ety_env
.substs
with
189 let (env
, x_ty
) = Env.expand_type env x_ty
in
190 (env
, mk
(Reason.Rinstantiate
(get_reason x_ty
, x
, r
), get_node x_ty
))
191 | None
-> (env
, mk
(r
, Tgeneric x
))
194 let (env
, ty) = localize ~ety_env env
ty in
195 TUtils.union env
(MakeType.null r
) ty
197 let (env
, ty) = localize ~ety_env env
ty in
198 let (env
, lty
) = TUtils.union env
(MakeType.dynamic r
) ty in
201 let pos = Reason.to_pos r
in
202 let (env
, ft
) = localize_ft ~ety_env ~def_pos
:pos env ft
in
203 (env
, mk
(r
, Tfun ft
))
204 | (r
, Tapply
((_
, x
), [arg
]))
205 when String.equal x
Naming_special_names.FB.cIncorrectType
206 && Env.is_typedef env x
->
207 localize ~ety_env env
(mk
(r
, Tlike arg
))
208 | (r
, Tapply
((_
, x
), argl
)) when Env.is_typedef env x
->
209 let (env
, argl
) = List.map_env env argl
(localize ~ety_env
) in
210 TUtils.expand_typedef ety_env env r x argl
211 | (r
, Tapply
(((p
, cid
) as cls
), argl
)) ->
213 match Env.get_class env cid
with
215 let (env
, tyl
) = List.map_env env argl
(localize ~ety_env
) in
216 (env
, mk
(r
, Tclass
(cls
, Nonexact
, tyl
)))
218 if Option.is_some
(Cls.enum_type class_info
) then
219 (* if argl <> [], nastInitCheck would have raised an error *)
220 match Typing_defs.has_expanded ety_env cid
with
222 Errors.cyclic_enum_constraint p
;
223 (env
, mk
(r
, Typing_utils.tany env
))
225 let type_expansions = (false, p
, cid
) :: ety_env
.type_expansions in
226 let ety_env = { ety_env with type_expansions } in
228 match Env.get_enum_constraint env cid
with
229 (* If not specified, default bound is arraykey *)
233 (Reason.Rimplicit_upper_bound
(p
, "arraykey")) )
234 | Some
ty -> localize ~
ety_env env
ty
236 (env
, mk
(r
, Tnewtype
(cid
, [], cstr
)))
238 let tparams = Cls.tparams class_info
in
241 TypecheckerOptions.global_inference
(Env.get_tcopt env
)
242 && (not
(List.is_empty
tparams))
243 && List.is_empty argl
245 (* In this case we will infer the missing type parameters *)
246 localize_missing_tparams_class env r cls class_info
248 localize_tparams ~
ety_env env
(Reason.to_pos r
) argl
tparams
250 (env
, mk
(r
, Tclass
(cls
, Nonexact
, tyl
)))
253 let (env
, tyl
) = List.map_env env tyl
(localize ~
ety_env) in
254 (env
, mk
(r
, Ttuple tyl
))
256 let (env
, tyl
) = List.map_env env tyl
(localize ~
ety_env) in
257 (env
, mk
(r
, Tunion tyl
))
258 | (r
, Tintersection tyl
) ->
259 let (env
, tyl
) = List.map_env env tyl
(localize ~
ety_env) in
260 (env
, mk
(r
, Tintersection tyl
))
261 | (r
, Taccess
(root_ty
, ids
)) ->
262 (* Sometimes, Tthis and Tgeneric are not expanded to Tabstract, so we need
263 to allow accessing abstract type constants here. *)
264 let allow_abstract_tconst =
265 match get_node root_ty
with
271 let (env
, root_ty
) = localize ~
ety_env env root_ty
in
273 List.fold ids ~init
:(env
, root_ty
) ~f
:(fun (env
, root_ty
) id
->
274 TUtils.expand_typeconst
279 ~on_error
:ety_env.on_error
280 ~
allow_abstract_tconst)
282 let (expansion_reason
, ty) = deref ety
in
283 (* Elaborate reason with information about expression dependent types and
284 * the original location of the Taccess type
286 let elaborate_reason expand_reason
=
287 (* First convert into a string of root_ty::ID1::ID2::IDn *)
291 (Typing_print.full_strip_ns env root_ty
:: List.map ~f
:snd ids
)
293 (* If the root is an expression dependent type, change the primary
294 * reason to be for the full Taccess type to preserve the position where
295 * the expression dependent type was derived from.
298 match get_reason root_ty
with
299 | Reason.Rexpr_dep_type
(_
, p
, e
) -> Reason.Rexpr_dep_type
(r
, p
, e
)
302 Reason.Rtype_access
(expand_reason
, [(reason, taccess_string)])
304 (env
, mk
(elaborate_reason expansion_reason
, ty))
305 | (r
, Tshape
(shape_kind
, tym
)) ->
306 let (env
, tym
) = ShapeFieldMap.map_env
(localize ~
ety_env) env tym
in
307 (env
, mk
(r
, Tshape
(shape_kind
, tym
)))
308 | (r
, Tpu_access
(dbase
, enum_or_tyname
)) ->
309 (* Env.get_upper_bounds might not be populated every time localization
310 * is called, but so far it is when it really matters, so we'll stick
311 * with this approximation: if no upper bounds info is available,
312 * localization will return a Tpu
314 let guess_if_pu env tp
=
315 let upper_bounds = Env.get_upper_bounds env tp
in
319 match get_node bound
with
327 let (env
, base
) = localize ~
ety_env env dbase
in
328 (match deref base
with
329 | (r
, Tgeneric tp
) ->
330 let member = (Reason.to_pos r
, tp
) in
331 if guess_if_pu env tp
then
332 (env
, mk
(r
, Tpu_type_access
(member, enum_or_tyname
)))
334 (env
, mk
(r
, Tpu
(base
, enum_or_tyname
)))
336 Typing_subtype_pocket_universes.get_tyvar_pu_access env r v enum_or_tyname
337 | _
-> (env
, mk
(r
, Tpu
(base
, enum_or_tyname
))))
339 and localize_tparams ~
ety_env env
pos tyl
tparams =
340 let length = min
(List.length tyl
) (List.length tparams) in
341 let (tyl
, tparams) = (List.take tyl
length, List.take
tparams length) in
342 let ((env
, _
), tyl
) =
343 List.map2_env
(env
, ety_env) tyl
tparams (localize_tparam
pos)
347 and localize_tparam
pos (env
, ety_env) ty tparam
=
349 | (r
, Tapply
((_
, x
), _argl
)) when String.equal x
SN.Typehints.wildcard
->
352 tp_constraints
= cstrl
;
353 tp_reified
= reified
;
360 Naming_attributes.mem
SN.UserAttributes.uaEnforceable tp_user_attributes
363 Naming_attributes.mem
SN.UserAttributes.uaNewable tp_user_attributes
365 let (env
, new_name
) =
366 Env.add_fresh_generic_parameter env name ~reified ~
enforceable ~
newable
368 let ty_fresh = mk
(r
, Tgeneric new_name
) in
369 (* Substitute fresh type parameters for original formals in constraint *)
370 let substs = SMap.add name
ty_fresh ety_env.substs in
371 let ety_env = { ety_env with substs } in
373 List.fold_left cstrl ~init
:env ~f
:(fun env (ck
, ty) ->
374 let (env, ty) = localize ~
ety_env env ty in
375 TUtils.add_constraint
pos env ck
ty_fresh ty)
377 ((env, ety_env), ty_fresh)
379 let (env, ty) = localize ~
ety_env env ty in
382 (* Recursive localizations of function types do not make judgements about enforceability *)
383 and localize_possibly_enforced_ty ~
ety_env env ety
=
384 let (env, et_type
) = localize ~
ety_env env ety
.et_type
in
385 (env, { ety
with et_type
})
387 and localize_cstr_ty ~
ety_env env ty tp_name
=
388 let (env, ety
) = localize ~
ety_env env ty in
389 let (r
, ty_
) = deref ety
in
390 let ty = mk
(Reason.Rcstr_on_generics
(Reason.to_pos r
, tp_name
), ty_
) in
393 (* Localize an explicit type argument to a constructor or function. We
394 * support the use of wildcards at the top level only *)
395 and localize_targ
env hint
=
396 let ty = Decl_hint.hint
env.decl_env hint
in
397 (* For explicit type arguments we support a wildcard syntax `_` for which
398 * Hack will generate a fresh type variable *)
400 | (r
, Tapply
((_
, id
), [])) when String.equal id
SN.Typehints.wildcard
->
401 let (env, ty) = Env.fresh_type
env (Reason.to_pos r
) in
404 let (env, ty) = localize_with_self
env ty in
407 (* See signature in .mli file for details *)
408 and localize_targs ~is_method ~def_pos ~use_pos ~use_name
env tparaml targl
=
409 let tparam_count = List.length tparaml
in
410 let targ_count = List.length targl
in
411 (* If there are explicit type arguments but too few or too many then
413 if Int.( <> ) targ_count 0 && Int.( <> ) tparam_count targ_count then
415 Errors.expected_tparam ~definition_pos
:def_pos ~use_pos
tparam_count None
420 ~expected
:tparam_count
423 (* Declare and localize the explicit type arguments *)
424 (* TODO? Drop surplus explicit type arguments *)
425 let (env, explicit_targs
) = List.map_env
env targl localize_targ
in
426 (* Generate fresh type variables for the remainder *)
427 let (env, implicit_targs
) =
428 List.map_env
env (List.drop tparaml
targ_count) (fun env tparam
->
430 Env.fresh_type_reason
432 (Reason.Rtype_variable_generics
433 (use_pos
, snd tparam
.tp_name
, use_name
))
435 Typing_log.log_tparam_instantiation
env use_pos tparam tvar
;
437 (tvar
, (use_pos
, Aast.Happly
((Pos.none
, SN.Typehints.wildcard
), [])))
440 (env, explicit_targs
@ implicit_targs
)
442 (* For the majority of cases when we localize a function type we instantiate
443 * the function's type parameters to be a Tunion wrapped in a Tvar so the
444 * type can grow. There are two cases where we do not do this.
446 * 1) In Typing_subtype.subtype_method. See the comment for that function for why
448 * 2) When the type arguments are explicitly specified, in which case we instantiate
449 * the type parameters to the provided types.
452 ?
(instantiation
: method_instantiation
option) ~
ety_env ~def_pos
env ft
=
453 (* set reactivity to Nonreactive to prevent occasional setting
454 of condition types when expanding type constants *)
455 let saved_r = env_reactivity
env in
456 let env = Env.set_env_reactive
env Nonreactive
in
457 (* If no explicit type parameters are provided, set the instantiated type parameter to
458 * initially point to unresolved, so that it can grow and eventually be a subtype of
459 * something like "mixed".
460 * If explicit type parameters are provided, just instantiate tvarl to them.
463 match instantiation
with
464 | Some
{ explicit_targs
; use_name
= _
; use_pos
} ->
466 (not
(List.is_empty explicit_targs
))
467 && Int.( <> ) (List.length explicit_targs
) (List.length ft
.ft_tparams
)
469 Errors.expected_tparam
470 ~definition_pos
:def_pos
472 (List.length ft
.ft_tparams
)
474 let tvarl = List.map ~f
:fst explicit_targs
in
475 let ft_subst = Subst.make_locl ft
.ft_tparams
tvarl in
476 (env, SMap.union
ft_subst ety_env.substs)
484 SMap.remove
(snd t
.tp_name
) subst
486 ~init
:ety_env.substs )
488 let ety_env = { ety_env with substs } in
489 (* restore reactivity *)
491 if not
(equal_reactivity
saved_r (env_reactivity
env)) then
492 Env.set_env_reactive
env saved_r
496 (* Localize the constraints for a type parameter declaration *)
497 let localize_tparam env t
=
499 List.map_env
env t
.tp_constraints
(fun env (ck
, ty) ->
500 let (env, ty) = localize_cstr_ty ~
ety_env env ty t
.tp_name
in
501 let name_str = snd t
.tp_name
in
502 (* In order to access type constants on generics on where clauses,
503 we need to add the constraints from the type parameters into the
504 environment before localizing the where clauses with them. Temporarily
505 add them to the environment here, and reset the environment later. *)
508 | Ast_defs.Constraint_as
-> Env.add_upper_bound
env name_str ty
509 | Ast_defs.Constraint_super
-> Env.add_lower_bound
env name_str ty
510 | Ast_defs.Constraint_eq
->
512 (Env.add_lower_bound
env name_str ty)
518 (env, { t
with tp_constraints
= cstrl
})
520 let localize_where_constraint env (ty1
, ck
, ty2
) =
521 let (env, ty1
) = localize ~
ety_env env ty1
in
522 let (env, ty2
) = localize ~
ety_env env ty2
in
523 (env, (ty1
, ck
, ty2
))
525 (* Grab and store the old tpenvs *)
526 let old_tpenv = Env.get_tpenv
env in
527 let old_global_tpenv = env.global_tpenv
in
528 (* Always localize tparams so they are available for later Tast check *)
529 let (env, tparams) = List.map_env
env ft
.ft_tparams
localize_tparam in
530 (* Localize the 'where' constraints *)
531 let (env, where_constraints
) =
532 List.map_env
env ft
.ft_where_constraints
localize_where_constraint
534 (* Remove the constraints we added for localizing where constraints *)
535 let env = Env.env_with_tpenv
env old_tpenv in
536 let env = Env.env_with_global_tpenv
env old_global_tpenv in
537 (* If we're instantiating the generic parameters then add a deferred
538 * check that constraints are satisfied under the
539 * substitution [ety_env.substs].
542 match instantiation
with
543 | Some
{ use_pos
; _
} ->
544 let env = check_tparams_constraints ~use_pos ~
ety_env env ft
.ft_tparams
in
546 check_where_constraints
549 ~definition_pos
:def_pos
552 ft
.ft_where_constraints
558 match ft
.ft_arity
with
559 | Fvariadic
({ fp_type
= var_ty
; _
} as param
) ->
560 let (env, var_ty
) = localize ~
ety_env env var_ty
.et_type
in
561 (* HHVM does not enforce types on vararg parameters yet *)
564 { param
with fp_type
= { et_type
= var_ty
; et_enforced
= false } } )
565 | Fstandard
as x
-> (env, x
)
568 List.map_env
env ft
.ft_params
(fun env param
->
570 localize_possibly_enforced_ty ~
ety_env env param
.fp_type
572 (env, { param
with fp_type
= ty }))
574 let (env, ret
) = localize_possibly_enforced_ty ~
ety_env env ft
.ft_ret
in
578 ( if Option.is_some instantiation
then
579 FTKinstantiated_targs
589 ft_tparams
= tparams;
590 ft_where_constraints
= where_constraints
;
593 (* Given a list of generic parameters [tparams] and a substitution
594 * in [ety_env.substs] whose domain is at least these generic parameters,
595 * check that the types satisfy
596 * the constraints on the corresponding generic parameter.
598 * Note that the constraints may contain occurrences of the generic
599 * parameters, but the subsitution will be applied to them. e.g. if tparams is
600 * <Tu as MyCovariant<Tu>, Tv super Tu>
601 * and ety_env.substs is
605 * class C extends MyContravariant<I> implements I { ... }
606 * Then the constraints are satisfied, because
607 * C is a subtype of MyContravariant<C>
608 * I is a supertype of C
610 and check_tparams_constraints ~use_pos ~
ety_env env tparams =
611 let check_tparam_constraints env t
=
612 List.fold_left t
.tp_constraints ~init
:env ~f
:(fun env (ck
, ty) ->
613 let (env, ty) = localize_cstr_ty ~
ety_env env ty t
.tp_name
in
614 match SMap.find_opt
(snd t
.tp_name
) ety_env.substs with
617 log_with_level
env "generics" 1 (fun () ->
623 ( "check_tparams_constraints: check_tparams_constraint",
624 [Log_type
("ty", ty); Log_type
("x_ty", x_ty
)] );
626 TGenConstraint.check_tparams_constraint
635 List.fold_left
tparams ~init
:env ~f
:check_tparam_constraints
637 and check_where_constraints
638 ~in_class ~use_pos ~
ety_env ~definition_pos
env cstrl
=
639 List.fold_left cstrl ~init
:env ~f
:(fun env (ty1
, ck
, ty2
) ->
640 let (env, ty1
) = localize ~
ety_env env ty1
in
641 let (env, ty2
) = localize ~
ety_env env ty2
in
642 TGenConstraint.check_where_constraint
651 (* Performs no substitutions of generics and initializes Tthis to
654 and localize_with_self
env ?
pos ?
(quiet
= false) ?report_cycle
ty =
655 let ety_env = env_with_self env ?
pos ~quiet ?report_cycle
in
656 localize env ty ~
ety_env
658 and localize_possibly_enforced_with_self
env ety
=
659 let (env, et_type
) = localize_with_self
env ety
.et_type
in
660 (env, { ety
with et_type
})
662 and localize_hint_with_self
env h
=
663 let h = Decl_hint.hint
env.decl_env
h in
664 localize_with_self
env h
666 and localize_hint ~
ety_env env hint
=
667 let hint_ty = Decl_hint.hint
env.decl_env hint
in
668 localize ~
ety_env env hint_ty
671 * If a type annotation for a class is missing type arguments, create a type variable
672 * for them and apply constraints.
674 * This is not used for local inference on constructors, but rather for global inference
675 * for partial files where function signatures are allowed to contain types ommitting type
678 and localize_missing_tparams_class
env r sid class_
=
679 let use_pos = Reason.to_pos r
in
680 let use_name = Utils.strip_ns
(snd sid
) in
681 let ((env, _i
), tyl
) =
682 List.fold_map
(Cls.tparams class_
) ~init
:(env, 0) ~f
:(fun (env, i
) tparam
->
687 (Reason.Rtype_variable_generics
688 (use_pos, snd tparam
.tp_name
, use_name))
692 let c_ty = mk
(r
, Tclass
(sid
, Nonexact
, tyl
)) in
695 type_expansions = [];
697 substs = Subst.make_locl
(Cls.tparams class_
) tyl
;
698 from_class
= Some
(Aast.CI sid
);
700 on_error
= Errors.unify_error_at
use_pos;
704 check_tparams_constraints ~
use_pos ~
ety_env env (Cls.tparams class_
)
707 check_where_constraints
710 ~definition_pos
:(Cls.pos class_
)
713 (Cls.where_constraints class_
)
717 and localize_targs_and_check_constraints
727 let (env, type_argl
) =
732 ~
use_name:(Utils.strip_ns
(snd class_id
))
737 let targs_tys = List.map ~f
:fst type_argl
in
739 mk
(Reason.Rwitness
(fst class_id
), Tclass
(class_id
, exact
, targs_tys))
742 if check_constraints
then
745 type_expansions = [];
747 substs = Subst.make_locl tparaml
targs_tys;
748 from_class
= Some from_class
;
750 on_error
= Errors.unify_error_at
use_pos;
753 check_tparams_constraints ~
use_pos ~
ety_env env tparaml
757 (env, this_ty, type_argl
)
759 (* Add generic parameters to the environment, localize their bounds, and
760 * transform these into a flat list of constraints of the form (ty1,ck,ty2)
761 * where ck is as, super or =
763 let localize_generic_parameters_with_bounds
764 ~
ety_env (env : env) (tparams : decl_tparam list
) =
765 let env = Env.add_generic_parameters
env tparams in
767 env ({ tp_name
= (pos, name
); tp_constraints
= cstrl
; _
} : decl_tparam
) =
768 let tparam_ty = mk
(Reason.Rwitness
pos, Tgeneric name
) in
769 List.map_env
env cstrl
(fun env (ck
, cstr
) ->
770 let (env, ty) = localize env cstr ~
ety_env in
771 (env, (tparam_ty, ck
, ty)))
773 let (env, cstrss
) = List.map_env
env tparams localize_bound in
774 (env, List.concat cstrss
)
776 let localize_where_constraints ~
ety_env (env : env) where_constraints
=
777 let add_constraint env (h1
, ck
, h2
) =
778 let (env, ty1
) = localize env (Decl_hint.hint
env.decl_env h1
) ~
ety_env in
779 let (env, ty2
) = localize env (Decl_hint.hint
env.decl_env h2
) ~
ety_env in
780 TUtils.add_constraint (fst h1
) env ck ty1 ty2
782 List.fold_left where_constraints ~f
:add_constraint ~init
:env
784 (* Helper functions *)
786 let sub_type_decl env ty1 ty2 on_error
=
787 let (env, ty1
) = localize_with_self
env ty1
in
788 let (env, ty2
) = localize_with_self
env ty2
in
789 let env = TUtils.sub_type
env ty1 ty2 on_error
in
792 let () = TUtils.localize_with_self_ref
:= localize_with_self