Move error detection for multiple :@ into naming
[hiphop-php.git] / hphp / hack / src / typing / typing_phase.ml
blob20a04705391585d5d7a44073e3dc8ed7238cd63a
1 (*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
10 open Hh_prelude
11 open Common
12 open Typing_defs
13 open Typing_env_types
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 ->
28 * match ty with
29 * | _, Tany -> "Any"
30 * | _ -> ""
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 =
36 * match phase_ty with
37 * | DeclTy 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
42 * are as follows.
44 * let yell_any_or_locl phase_ty =
45 * let ans = yell_locl phase_ty in
46 * match phase_ty with
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
52 * two options.
54 * let generic_ty: type a. phase_ty -> a ty = function
55 * | DeclTy ty -> ty
56 * | LoclTy ty -> ty
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
64 * is.
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
70 * ans ^ (yell_any ty)
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 = {
81 use_pos: Pos.t;
82 use_name: string;
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
89 type_expansions =
90 begin
91 match report_cycle with
92 | None -> []
93 | Some (pos, id) -> [(true, pos, id)]
94 end;
95 substs = SMap.empty;
96 this_ty;
97 from_class = None;
98 quiet;
99 on_error =
100 (match pos with
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
111 * > ...
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)
123 then
124 Env.new_global_tyvar env ~i r
125 else
126 localize ~ety_env env ty
128 match deref dty with
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)
134 | (r, Tthis) ->
135 let ty =
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)
141 | (reason, ty) ->
142 mk (Reason.Rinstantiate (reason, SN.Typehints.this, r), ty)
144 let (env, ty) =
145 match ety_env.from_class with
146 | Some cid -> ExprDepTy.make env cid ty
147 | _ -> (env, ty)
149 (env, ty)
150 | (r, Tarray (ty1, ty2)) ->
151 let (env, ty) =
152 match (ty1, ty2) with
153 | (None, None) ->
154 let tk = MakeType.arraykey Reason.(Rvarray_or_darray_key (to_pos r)) in
155 let (env, tv) =
156 if GlobalOptions.tco_global_inference env.genv.tcopt then
157 Env.new_global_tyvar env r
158 else
159 (env, mk (r, TUtils.tany env))
161 (env, Tvarray_or_darray (tk, tv))
162 | (Some tv, None) ->
163 let (env, tv) = tvar_or_localize ~ety_env env r tv ~i:1 in
164 (env, Tvarray tv)
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"
171 (env, mk (r, ty))
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
176 (env, mk (r, ty))
177 | (r, Tvarray tv) ->
178 let (env, tv) = tvar_or_localize ~ety_env env r tv ~i:0 in
179 let ty = Tvarray tv in
180 (env, mk (r, ty))
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)
185 | (r, Tgeneric x) ->
186 begin
187 match SMap.find_opt x ety_env.substs with
188 | Some x_ty ->
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))
193 | (r, Toption ty) ->
194 let (env, ty) = localize ~ety_env env ty in
195 TUtils.union env (MakeType.null r) ty
196 | (r, Tlike ty) ->
197 let (env, ty) = localize ~ety_env env ty in
198 let (env, lty) = TUtils.union env (MakeType.dynamic r) ty in
199 (env, lty)
200 | (r, Tfun ft) ->
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)) ->
212 begin
213 match Env.get_class env cid with
214 | None ->
215 let (env, tyl) = List.map_env env argl (localize ~ety_env) in
216 (env, mk (r, Tclass (cls, Nonexact, tyl)))
217 | Some class_info ->
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
221 | Some _ ->
222 Errors.cyclic_enum_constraint p;
223 (env, mk (r, Typing_utils.tany env))
224 | None ->
225 let type_expansions = (false, p, cid) :: ety_env.type_expansions in
226 let ety_env = { ety_env with type_expansions } in
227 let (env, cstr) =
228 match Env.get_enum_constraint env cid with
229 (* If not specified, default bound is arraykey *)
230 | None ->
231 ( env,
232 MakeType.arraykey
233 (Reason.Rimplicit_upper_bound (p, "arraykey")) )
234 | Some ty -> localize ~ety_env env ty
236 (env, mk (r, Tnewtype (cid, [], cstr)))
237 else
238 let tparams = Cls.tparams class_info in
239 let (env, tyl) =
241 TypecheckerOptions.global_inference (Env.get_tcopt env)
242 && (not (List.is_empty tparams))
243 && List.is_empty argl
244 then
245 (* In this case we will infer the missing type parameters *)
246 localize_missing_tparams_class env r cls class_info
247 else
248 localize_tparams ~ety_env env (Reason.to_pos r) argl tparams
250 (env, mk (r, Tclass (cls, Nonexact, tyl)))
252 | (r, Ttuple tyl) ->
253 let (env, tyl) = List.map_env env tyl (localize ~ety_env) in
254 (env, mk (r, Ttuple tyl))
255 | (r, Tunion 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
266 | Tthis
267 | Tgeneric _ ->
268 true
269 | _ -> false
271 let (env, root_ty) = localize ~ety_env env root_ty in
272 let (env, ety) =
273 List.fold ids ~init:(env, root_ty) ~f:(fun (env, root_ty) id ->
274 TUtils.expand_typeconst
275 ety_env
277 root_ty
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 *)
288 let taccess_string =
289 String.concat
290 ~sep:"::"
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.
297 let reason =
298 match get_reason root_ty with
299 | Reason.Rexpr_dep_type (_, p, e) -> Reason.Rexpr_dep_type (r, p, e)
300 | _ -> r
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
316 let res =
317 Typing_set.fold
318 (fun bound res ->
319 match get_node bound with
320 | Tpu (_, _) -> true
321 | _ -> res)
322 upper_bounds
323 false
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)))
333 else
334 (env, mk (r, Tpu (base, enum_or_tyname)))
335 | (r, Tvar v) ->
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)
345 (env, tyl)
347 and localize_tparam pos (env, ety_env) ty tparam =
348 match deref ty with
349 | (r, Tapply ((_, x), _argl)) when String.equal x SN.Typehints.wildcard ->
350 let {
351 tp_name = (_, name);
352 tp_constraints = cstrl;
353 tp_reified = reified;
354 tp_user_attributes;
357 tparam
359 let enforceable =
360 Naming_attributes.mem SN.UserAttributes.uaEnforceable tp_user_attributes
362 let newable =
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
372 let env =
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)
378 | _ ->
379 let (env, ty) = localize ~ety_env env ty in
380 ((env, ety_env), ty)
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
391 (env, ty)
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 *)
399 match deref ty with
400 | (r, Tapply ((_, id), [])) when String.equal id SN.Typehints.wildcard ->
401 let (env, ty) = Env.fresh_type env (Reason.to_pos r) in
402 (env, (ty, hint))
403 | _ ->
404 let (env, ty) = localize_with_self env ty in
405 (env, (ty, hint))
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
412 * report an error *)
413 if Int.( <> ) targ_count 0 && Int.( <> ) tparam_count targ_count then
414 if is_method then
415 Errors.expected_tparam ~definition_pos:def_pos ~use_pos tparam_count None
416 else
417 Errors.type_arity
418 use_pos
419 def_pos
420 ~expected:tparam_count
421 ~actual:targ_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 ->
429 let (env, tvar) =
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;
436 ( env,
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
447 * this is necessary.
448 * 2) When the type arguments are explicitly specified, in which case we instantiate
449 * the type parameters to the provided types.
451 and localize_ft
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.
462 let (env, substs) =
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)
468 then
469 Errors.expected_tparam
470 ~definition_pos:def_pos
471 ~use_pos
472 (List.length ft.ft_tparams)
473 None;
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)
477 | None ->
478 ( env,
479 List.fold_left
480 ft.ft_tparams
482 begin
483 fun subst t ->
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 *)
490 let env =
491 if not (equal_reactivity saved_r (env_reactivity env)) then
492 Env.set_env_reactive env saved_r
493 else
496 (* Localize the constraints for a type parameter declaration *)
497 let localize_tparam env t =
498 let (env, cstrl) =
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. *)
506 let env =
507 match ck with
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 ->
511 Env.add_upper_bound
512 (Env.add_lower_bound env name_str ty)
513 name_str
516 (env, (ck, 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].
541 let env =
542 match instantiation with
543 | Some { use_pos; _ } ->
544 let env = check_tparams_constraints ~use_pos ~ety_env env ft.ft_tparams in
545 let env =
546 check_where_constraints
547 ~in_class:false
548 ~use_pos
549 ~definition_pos:def_pos
550 ~ety_env
552 ft.ft_where_constraints
555 | None -> env
557 let (env, arity) =
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 *)
562 ( env,
563 Fvariadic
564 { param with fp_type = { et_type = var_ty; et_enforced = false } } )
565 | Fstandard as x -> (env, x)
567 let (env, params) =
568 List.map_env env ft.ft_params (fun env param ->
569 let (env, ty) =
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
575 let ft =
576 set_ft_ftk
578 ( if Option.is_some instantiation then
579 FTKinstantiated_targs
580 else
581 FTKtparams )
583 ( env,
585 ft with
586 ft_arity = arity;
587 ft_params = params;
588 ft_ret = ret;
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
602 * Tu :-> C
603 * Tv :-> I
604 * with
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
615 | Some x_ty ->
616 Typing_log.(
617 log_with_level env "generics" 1 (fun () ->
618 log_types
619 use_pos
622 Log_head
623 ( "check_tparams_constraints: check_tparams_constraint",
624 [Log_type ("ty", ty); Log_type ("x_ty", x_ty)] );
625 ]));
626 TGenConstraint.check_tparams_constraint
628 ~use_pos
629 t.tp_name
632 x_ty
633 | None -> env)
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
643 ~in_class
645 ~use_pos
646 ~definition_pos
649 ty1)
651 (* Performs no substitutions of generics and initializes Tthis to
652 * Env.get_self env
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
676 * arguments.
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 ->
683 let (env, ty) =
684 Env.new_global_tyvar
687 (Reason.Rtype_variable_generics
688 (use_pos, snd tparam.tp_name, use_name))
690 ((env, i + 1), ty))
692 let c_ty = mk (r, Tclass (sid, Nonexact, tyl)) in
693 let ety_env =
695 type_expansions = [];
696 this_ty = c_ty;
697 substs = Subst.make_locl (Cls.tparams class_) tyl;
698 from_class = Some (Aast.CI sid);
699 quiet = false;
700 on_error = Errors.unify_error_at use_pos;
703 let env =
704 check_tparams_constraints ~use_pos ~ety_env env (Cls.tparams class_)
706 let env =
707 check_where_constraints
708 ~in_class:true
709 ~use_pos
710 ~definition_pos:(Cls.pos class_)
711 ~ety_env
713 (Cls.where_constraints class_)
715 (env, tyl)
717 and localize_targs_and_check_constraints
718 ~exact
719 ~check_constraints
720 ~def_pos
721 ~use_pos
723 class_id
724 from_class
725 tparaml
726 hintl =
727 let (env, type_argl) =
728 localize_targs
729 ~is_method:false
730 ~def_pos
731 ~use_pos
732 ~use_name:(Utils.strip_ns (snd class_id))
734 tparaml
735 hintl
737 let targs_tys = List.map ~f:fst type_argl in
738 let this_ty =
739 mk (Reason.Rwitness (fst class_id), Tclass (class_id, exact, targs_tys))
741 let env =
742 if check_constraints then
743 let ety_env =
745 type_expansions = [];
746 this_ty;
747 substs = Subst.make_locl tparaml targs_tys;
748 from_class = Some from_class;
749 quiet = false;
750 on_error = Errors.unify_error_at use_pos;
753 check_tparams_constraints ~use_pos ~ety_env env tparaml
754 else
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
766 let localize_bound
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