sync the repo
[hiphop-php.git] / hphp / hack / src / typing / typing_phase.ml
blobdd648af45c865ed26ccc26c19f73e87a2d7f3086
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 module Env = Typing_env
15 module TUtils = Typing_utils
16 module TGenConstraint = Typing_generic_constraint
17 module Subst = Decl_subst
18 module MakeType = Typing_make_type
19 module Cls = Folded_class
20 module KindDefs = Typing_kinding_defs
21 module TIntegrity = Typing_type_integrity
22 module SN = Naming_special_names
24 (* Here is the general problem the delayed application of the phase solves.
25 * Let's say you have a function that you want to operate generically across
26 * phases. In most cases when you do this you can use the 'ty' GADT and locally
27 * abstract types to write code in a phase agonistic way.
29 * let yell_any: type a. a ty -> string = fun ty ->
30 * match ty with
31 * | _, Tany -> "Any"
32 * | _ -> ""
34 * Now let's add a function that works for all phases, but whose logic is phase
35 * dependent. For this we can use 'phase_ty' ADT:
37 * let yell_locl phase_ty =
38 * match phase_ty with
39 * | DeclTy ty -> ""
40 * | LoclTy ty -> "Locl"
42 * Let's say you want to write a function that has behavior that works across
43 * phases, but needs to invoke a function that is phase dependent. Our options
44 * are as follows.
46 * let yell_any_or_locl phase_ty =
47 * let ans = yell_locl phase_ty in
48 * match phase_ty with
49 * | DeclTy ty -> ans ^ (yell_any ty)
50 * | LoclTy ty -> ans ^ (yell_any ty)
52 * This would lead to code duplication since we can't generically operate on the
53 * underlying 'ty' GADT. If we want to eliminate this code duplication there are
54 * two options.
56 * let generic_ty: type a. phase_ty -> a ty = function
57 * | DeclTy ty -> ty
58 * | LoclTy ty -> ty
60 * let yell_any_or_locl phase_ty =
61 * let ans = yell_locl phase_ty in
62 * ans ^ (yell_any (generic_ty phase_ty))
64 * generic_ty allows us to extract a generic value which we can use. This
65 * approach is limiting because we lose all information about what phase 'a ty
66 * is.
68 * The other approach is to pass in a function that goes from 'a ty -> phase_ty'
70 * let yell_any_or_locl phase ty =
71 * let ans = yell_locl (phase ty) in
72 * ans ^ (yell_any ty)
74 * Here we can use 'ty' generically (without losing information about what phase
75 * 'a ty' is), and we rely on the caller passing in an appropriate function that
76 * converts into the 'phase_ty' when we need to hop into phase specific code.
78 let decl ty = DeclTy ty
80 let locl ty = LoclTy ty
82 type method_instantiation = {
83 use_pos: Pos.t;
84 use_name: string;
85 explicit_targs: Tast.targ list;
88 (*****************************************************************************)
89 (* Localization caching. *)
90 (*****************************************************************************)
92 module type CACHESETTINGS = sig
93 val capacity : int
95 val node_count_threshold : int
96 end
98 module MakeTyCache (Settings : CACHESETTINGS) : sig
99 val add : env -> string -> locl_ty -> unit
101 val get : env -> string -> locl_ty option
102 end = struct
103 include
104 Lru.M.Make
105 (String)
106 (struct
107 type t = locl_ty
109 let weight _ = 1
110 end)
112 let cache = create Settings.capacity
114 let should_cache_type lty =
115 let exception NodeLimitReached in
116 let size_visitor =
117 object
118 inherit [int] Type_visitor.locl_type_visitor as super
120 method! on_type acc ty =
121 if acc >= Settings.node_count_threshold then raise NodeLimitReached;
122 super#on_type (acc + 1) ty
125 match size_visitor#on_type 0 lty with
126 | _count -> false
127 | exception NodeLimitReached -> true
129 let clear () =
130 (* The only reliable way to empty the LRU cache. *)
131 resize 0 cache;
132 trim cache;
133 resize Settings.capacity cache;
134 assert (is_empty cache)
136 let active_context = ref (Relative_path.default, None)
138 (* We invalidate the cache as soon as we are processing a new file or
139 * module because those affect how types are expanded (e.g., newtypes
140 * are unfolded only in the file that defines them). *)
141 let maybe_invalidate env =
142 let context = (Env.get_file env, Env.get_current_module env) in
143 let valid =
144 [%eq: Relative_path.t * string option] !active_context context
146 if not valid then begin
147 active_context := context;
148 clear ()
151 let add env alias lty =
152 let () = maybe_invalidate env in
153 if should_cache_type lty then begin
154 add alias lty cache;
155 trim cache
158 let get env alias =
159 let () = maybe_invalidate env in
160 promote alias cache;
161 find alias cache
164 (* Since the typechecker options defining the cache parameters will be
165 * available only when we have an environment, the add/get functions are
166 * stored in references initially set to stubs that update themselves
167 * during their first call. *)
168 let rec locl_cache_add =
169 ref (fun env ->
170 setup_cache env;
171 !locl_cache_add env)
173 and locl_cache_get =
174 ref (fun env ->
175 setup_cache env;
176 !locl_cache_get env)
178 and setup_cache env =
179 let tcopts = Env.get_tcopt env in
180 let module Settings = struct
181 let capacity = TypecheckerOptions.locl_cache_capacity tcopts
183 let node_count_threshold =
184 TypecheckerOptions.locl_cache_node_threshold tcopts
185 end in
186 let module Cache = MakeTyCache (Settings) in
187 locl_cache_add := Cache.add;
188 locl_cache_get := Cache.get
190 (*****************************************************************************)
191 (* Transforms a declaration phase type into a localized type. This performs
192 * common operations that are necessary for this operation, specifically:
193 * > Expand newtype/types
194 * > Resolves the "this" type
195 * > Instantiate generics
196 * > ...
198 * When keep track of additional information while localizing a type such as
199 * what type defs were expanded to detect potentially recursive definitions..
201 (*****************************************************************************)
203 let rec localize ~(ety_env : expand_env) env (dty : decl_ty) =
204 (fun ((env, ty_err_opt), ty) ->
205 let (env, ty) = Typing_log.log_localize ~level:1 ety_env dty (env, ty) in
206 ((env, ty_err_opt), ty))
208 let rec find_origin dty =
209 match get_node dty with
210 | Taccess (root_ty, (_pos, id)) ->
211 Option.map ~f:(fun orig -> orig ^ "::" ^ id) (find_origin root_ty)
212 | Tapply ((_pos, cid), []) -> Some cid
213 | _ -> None
215 let set_origin_and_cache origin_opt final_env ty_err_opt lty decl_pos_opt =
216 (* When the type resulting from the localize call originates from a
217 * decl type with a succinct unambiguous form (e.g., Cls or Cls::T) we
218 * store a serialized version of the decl alias in an *origin* field
219 * of the locl type returned. Currently, only shape types have an
220 * origin field. *)
221 let cache_result () =
222 (* Under the following conditions we may cache the localized
223 * type:
225 * 1/ We did not encounter cycles during expansion,
226 * 2/ localization was error-free,
227 * 3/ we are expanding under regular assumptions (local
228 * newtypes are visible), and
229 * 4/ the expansion has not created new global type params.
231 * Case 4 happens when we bogusly create type params for
232 * abstract type constants.
233 * Cycles are not reported systematically as errors, so we
234 * track them separately with a reference in ety_env. *)
235 let no_new_global_type_params =
236 Type_parameter_env.size final_env.tpenv
237 <= Type_parameter_env.size env.tpenv
239 (not (Typing_defs.cyclic_expansion ety_env))
240 && Option.is_none ty_err_opt
241 && ety_env.expand_visible_newtype
242 && ety_env.make_internal_opaque
243 && no_new_global_type_params
245 match deref lty with
246 | ( r,
247 Tshape
249 s_origin = _;
250 s_unknown_value = shape_kind;
251 s_fields = shape_fields;
252 } ) -> begin
253 match origin_opt with
254 | None -> lty
255 | Some origin ->
256 let lty =
258 ( r,
259 Tshape
261 s_origin = From_alias (origin, decl_pos_opt);
262 s_unknown_value = shape_kind;
263 s_fields = shape_fields;
266 if cache_result () then !locl_cache_add env origin lty;
269 | _ -> lty
271 let push_supportdyn_into_shape lty =
272 let (is_supportdyn, _env, stripped_lty) = TUtils.strip_supportdyn env lty in
273 match deref stripped_lty with
274 | ( r,
275 Tshape
276 { s_origin = origin; s_unknown_value = ty; s_fields = shape_fields }
278 when is_supportdyn ->
279 MakeType.supportdyn
282 ( r,
283 Tshape
285 s_origin = origin;
286 s_unknown_value = MakeType.supportdyn r ty;
287 s_fields = shape_fields;
288 } ))
289 | _ -> lty
291 let r = get_reason dty |> Typing_reason.localize in
292 match get_node dty with
293 | Trefinement (root, cr) -> localize_refinement ~ety_env env r root cr
294 | (Tnonnull | Tprim _ | Tdynamic | Tany _) as x -> ((env, None), mk (r, x))
295 | Tmixed -> ((env, None), MakeType.mixed r)
296 | Tthis ->
297 let ty =
298 map_reason ety_env.this_ty ~f:(function reason ->
299 if Reason.Predicates.is_none reason then
301 else (
302 match Reason.Predicates.unpack_expr_dep_type_opt reason with
303 | Some (_, pos, s) -> Reason.expr_dep_type (r, pos, s)
304 | None -> Reason.instantiate (reason, SN.Typehints.this, r)
307 (* When refining `as this`, insert a like type for generic or non-final
308 * classes, because generics are not checked at runtime *)
309 let ty =
310 if ety_env.ish_weakening then
311 match Env.get_self_class env with
312 | Decl_entry.Found tc ->
313 if Cls.final tc && List.is_empty (Cls.tparams tc) then
315 else
316 MakeType.locl_like (Reason.pessimised_this (Reason.to_pos r)) ty
317 | _ -> ty
318 else
321 ((env, None), ty)
322 | Tvec_or_dict (tk, tv) ->
323 let ((env, e1), tk) = localize ~ety_env env tk in
324 let ((env, e2), tv) = localize ~ety_env env tv in
325 let ty = Tvec_or_dict (tk, tv) in
326 let ty_err_opt = Option.merge e1 e2 ~f:Typing_error.both in
327 ((env, ty_err_opt), mk (r, ty))
328 | Tgeneric (x, targs) ->
329 let localize_tgeneric ?replace_with name r =
330 match (targs, replace_with, Env.get_pos_and_kind_of_generic env name) with
331 | (_, _, Some (_def_pos, kind)) ->
332 let arg_kinds : KindDefs.Simple.named_kind list =
333 KindDefs.Simple.from_full_kind kind
334 |> KindDefs.Simple.get_named_parameter_kinds
336 begin
337 match
338 ( localize_targs_by_kind
339 ~ety_env:{ ety_env with expand_visible_newtype = true }
341 targs
342 arg_kinds,
343 replace_with )
344 with
345 | ((env, _), Some repl_ty) -> (env, mk (r, repl_ty))
346 | ((env, locl_tyargs), None) ->
347 (env, mk (r, Tgeneric (name, locl_tyargs)))
349 | ([], None, None) ->
350 (* No kinding info, but also no type arguments. Just return Tgeneric *)
351 ((env, None), mk (r, Tgeneric (x, [])))
352 | ([], Some repl_ty, None) -> ((env, None), mk (r, repl_ty))
353 | (_ :: _, _, None) ->
354 (* No kinding info, but type arguments given. We don't know the kinds of the arguments,
355 so we can't localize them. Not much we can do. *)
356 let (env, ty) = Env.fresh_type_error env Pos.none in
357 ((env, None), ty)
359 begin
360 match SMap.find_opt x ety_env.substs with
361 | Some x_ty ->
362 let (env, x_ty) = Env.expand_type env x_ty in
363 let r_inst =
364 let rp = get_reason x_ty in
365 if not @@ TypecheckerOptions.using_extended_reasons env.genv.tcopt
366 then
367 Reason.instantiate (rp, x, r)
368 else
371 begin
372 match (targs, get_node x_ty) with
373 | (_ :: _, Tclass (((_, name) as id), _, [])) ->
374 let class_info = Env.get_class env name in
375 localize_class_instantiation
376 ~ety_env
378 r_inst
380 targs
381 (Decl_entry.to_option class_info)
382 | (_ :: _, Tnewtype (id, [], _))
383 | (_ :: _, Tunapplied_alias id) ->
384 localize_typedef_instantiation
385 ~ety_env
387 r_inst
389 targs
390 (Env.get_typedef env id |> Decl_entry.to_option)
391 | (_ :: _, Tgeneric (x', [])) -> localize_tgeneric x' r_inst
392 | (_, ty_) -> ((env, None), mk (r_inst, ty_))
394 | None -> localize_tgeneric x r
396 | Toption ty ->
397 let ((env, ty_err_opt), ty) = localize ~ety_env env ty in
398 (* Calling into the union module here would cost 2% perf regression on a full init,
399 * so we use this lightweight version instead. *)
400 let union_null env ty =
401 let rec null_is_subtype_of ty =
402 match get_node ty with
403 | Toption _
404 | Tprim Aast.Tnull ->
405 true
406 | Tunion tyl -> List.exists tyl ~f:null_is_subtype_of
407 | Tintersection tyl -> List.for_all tyl ~f:null_is_subtype_of
408 | _ -> false
410 if null_is_subtype_of ty then
411 (env, ty)
412 else
413 MakeType.nullable r ty |> TUtils.wrap_union_inter_ty_in_var env r
415 let (env, ty) = union_null env ty in
416 ((env, ty_err_opt), ty)
417 | Tlike ty ->
418 let ((env, ty_err_opt), ty) = localize ~ety_env env ty in
419 let lty = MakeType.locl_like r ty in
420 ((env, ty_err_opt), lty)
421 | Tfun ft ->
422 let pos = Reason.to_pos r in
423 let (env, ft) = localize_ft ~ety_env ~def_pos:pos env ft in
424 (env, mk (r, Tfun ft))
425 | Tapply ((_, x), [arg]) when String.equal x SN.HH.FIXME.tPoisonMarker ->
426 let decl_ty =
427 if TypecheckerOptions.enable_sound_dynamic (Env.get_tcopt env) then
428 mk (get_reason dty, Tlike arg)
429 else
432 localize ~ety_env env decl_ty
433 | Twildcard -> begin
434 match ety_env.wildcard_action with
435 (* Generate a fresh type variable *)
436 | Wildcard_fresh_tyvar ->
437 let (env, ty) =
438 Env.fresh_type env (Pos_or_decl.unsafe_to_raw_pos (Reason.to_pos r))
440 ((env, None), ty)
441 (* Produce an error: wildcard is not allowed in this position *)
442 | Wildcard_require_explicit tparam ->
443 let (decl_pos, param_name) = tparam.tp_name in
444 let err_opt =
445 Some
446 Typing_error.(
447 primary
448 @@ Primary.Require_generic_explicit
450 decl_pos;
451 param_name;
452 pos = Pos_or_decl.unsafe_to_raw_pos (Reason.to_pos r);
455 let (env, ty) =
456 Env.fresh_type_error
458 (Pos_or_decl.unsafe_to_raw_pos (Reason.to_pos r))
460 ((env, err_opt), ty)
461 (* All should have been dealt with already:
462 * (1) Wildcard_fresh_generic and Wildcard_fresh_generic_type_argument, in localize_targ_by_kind.
463 * (2) Wildcard_illegal, in the naming phase.
464 * (3) Wildcard_higher_kinded_placeholder, in Typing_type_integrity.ml
466 | Wildcard_fresh_generic
467 | Wildcard_illegal
468 | Wildcard_higher_kinded_placeholder ->
469 let (env, ty) =
470 Env.fresh_type_error
472 (Pos_or_decl.unsafe_to_raw_pos (Reason.to_pos r))
474 ((env, None), ty)
476 | Tapply (((_p, cid) as cls), argl) ->
477 let (env_err, lty) =
478 match Env.get_class_or_typedef env cid with
479 | Decl_entry.Found (Env.ClassResult class_info) ->
480 localize_class_instantiation ~ety_env env r cls argl (Some class_info)
481 | Decl_entry.Found (Env.TypedefResult typedef_info) ->
482 let origin_opt = find_origin dty in
483 let ((env, ty_err_opt), lty) =
484 match Option.bind origin_opt ~f:(!locl_cache_get env) with
485 | Some lty -> ((env, None), with_reason lty r)
486 | None ->
487 localize_typedef_instantiation
488 ~ety_env
492 argl
493 (Some typedef_info)
495 let shp_def_pos =
496 Reason.to_pos @@ Typing_defs.get_reason typedef_info.td_type
498 let lty =
499 set_origin_and_cache origin_opt env ty_err_opt lty (Some shp_def_pos)
501 let lty =
502 Typing_env.update_reason env lty ~f:(fun r ->
503 Typing_reason.(definition typedef_info.td_pos r))
505 ((env, ty_err_opt), lty)
506 | Decl_entry.DoesNotExist
507 | Decl_entry.NotYetAvailable ->
508 localize_class_instantiation ~ety_env env r cls argl None
510 let lty =
511 (* If we have supportdyn<t> then push supportdyn into open shape fields *)
512 if String.equal cid SN.Classes.cSupportDyn then
513 push_supportdyn_into_shape lty
514 else
517 (env_err, lty)
518 | Ttuple tyl ->
519 let (env, tyl) =
520 List.map_env_ty_err_opt
523 ~f:(localize ~ety_env)
524 ~combine_ty_errs:Typing_error.multiple_opt
526 (env, mk (r, Ttuple tyl))
527 | Tunion tyl ->
528 let ((env, ty_err_opt), tyl) =
529 List.map_env_ty_err_opt
532 ~f:(localize ~ety_env)
533 ~combine_ty_errs:Typing_error.union_opt
535 let (env, ty) = Typing_union.union_list env r tyl in
536 ((env, ty_err_opt), ty)
537 | Tintersection tyl ->
538 let ((env, ty_err_opt), tyl) =
539 List.map_env_ty_err_opt
542 ~f:(localize ~ety_env)
543 ~combine_ty_errs:Typing_error.multiple_opt
545 let (env, ty) = Typing_intersection.intersect_list env r tyl in
546 ((env, ty_err_opt), ty)
547 | Taccess (root_ty, id) ->
548 let origin_opt = find_origin dty in
549 (match Option.bind origin_opt ~f:(!locl_cache_get env) with
550 | Some lty -> ((env, None), with_reason lty r)
551 | None ->
552 let rec allow_abstract_tconst ty =
553 match get_node ty with
554 | Tthis
555 | Tgeneric _ ->
557 * When the root of an access is 'this', abstract type constants
558 * are allowed and localized as rigid type variables (Tgeneric).
559 * This happens when typing generic code in an abstract class
560 * that deals with data whose type is going to be set later in
561 * derived classes.
563 * In case the root is a generic, we also accept accesses to
564 * abstract constant to type check the dangerous and ubiquitous
565 * pattern:
567 * function get<TBox as Box, T>(TBox $foo) : T where T = TBox::T
568 * ^^^^^^^
570 true
571 | Taccess (ty, _) -> allow_abstract_tconst ty
572 | _ -> false
574 let allow_abstract_tconst = allow_abstract_tconst root_ty in
575 let ((env, e1), root_ty) =
576 (* We don't want to put `~` on this::TC, so set ish_weakening to false *)
577 localize ~ety_env:{ ety_env with ish_weakening = false } env root_ty
579 let ((env, e2), ty) =
580 TUtils.expand_typeconst ety_env env root_ty id ~allow_abstract_tconst
582 (* Elaborate reason with information about expression dependent types and
583 * the original location of the Taccess type
585 let ty_err_opt = Option.merge e1 e2 ~f:Typing_error.both in
586 let ty = set_origin_and_cache origin_opt env ty_err_opt ty None in
587 let elaborate_reason expand_reason =
588 let taccess_string =
589 lazy (Typing_print.full_strip_ns env root_ty ^ "::" ^ snd id)
591 (* If the root is an expression dependent type, change the primary
592 * reason to be for the full Taccess type to preserve the position where
593 * the expression dependent type was derived from.
595 let reason =
596 match
597 Reason.Predicates.unpack_expr_dep_type_opt (get_reason root_ty)
598 with
599 | Some (_, p, e) -> Reason.expr_dep_type (r, p, e)
600 | None -> r
602 Reason.type_access (expand_reason, [(reason, taccess_string)])
604 let ty = map_reason ty ~f:elaborate_reason in
605 ((env, ty_err_opt), ty))
606 | Tshape { s_origin = _; s_unknown_value = shape_kind; s_fields = tym } ->
607 let ((env, ty_err_opt1), tym) =
608 ShapeFieldMap.map_env_ty_err_opt
609 (localize ~ety_env)
612 ~combine_ty_errs:Typing_error.multiple_opt
614 let ((env, ty_err_opt2), shape_kind) = localize ~ety_env env shape_kind in
615 let ty_err_opt =
616 Option.merge ty_err_opt1 ty_err_opt2 ~f:Typing_error.both
618 ( (env, ty_err_opt),
620 ( r,
621 Tshape
623 s_origin = Missing_origin;
624 s_unknown_value = shape_kind;
625 s_fields = tym;
626 } ) )
627 | Tnewtype (name, tyl, ty) ->
628 let td =
629 Decl_provider.get_typedef (Env.get_ctx env) name
630 |> Decl_entry.to_option
631 |> Utils.unsafe_opt
633 let should_expand =
634 Env.is_typedef_visible
636 ~expand_visible_newtype:ety_env.expand_visible_newtype
637 ~name
640 if should_expand then
641 let decl_pos = Reason.to_pos r in
642 let (ety_env, has_cycle) =
643 Typing_defs.add_type_expansion_check_cycles ety_env (decl_pos, name)
645 match has_cycle with
646 | Some initial_taccess_pos_opt ->
647 let ty_err_opt =
648 Option.map initial_taccess_pos_opt ~f:(fun initial_taccess_pos ->
649 Typing_error.(
650 primary
651 @@ Primary.Cyclic_typedef
652 { def_pos = initial_taccess_pos; use_pos = decl_pos }))
654 let (env, ty) =
655 Env.fresh_type_error env (Pos_or_decl.unsafe_to_raw_pos decl_pos)
657 ((env, ty_err_opt), ty)
658 | None ->
659 Decl_typedef_expand.expand_typedef
660 ~force_expand:true
661 (Env.get_ctx env)
662 (get_reason dty)
663 name
665 |> localize ~ety_env env
666 else
667 let ((env, e1), ty) = localize ~ety_env env ty in
668 let ((env, e2), tyl) =
669 List.map_env_ty_err_opt
672 ~f:(localize ~ety_env)
673 ~combine_ty_errs:Typing_error.multiple_opt
675 let ty_err_opt = Option.merge e1 e2 ~f:Typing_error.both in
676 ((env, ty_err_opt), mk (r, Tnewtype (name, tyl, ty)))
678 (* Localize type arguments for something whose kinds is [kind] *)
679 and localize_targs_by_kind
680 ~ety_env
682 (tyargs : decl_ty list)
683 (nkinds : KindDefs.Simple.named_kind list) =
684 let exp_len = List.length nkinds in
685 let act_len = List.length tyargs in
686 let length = min exp_len act_len in
687 let (tyargs, nkinds) = (List.take tyargs length, List.take nkinds length) in
688 let ((env, ty_errs, _), tyl) =
689 List.map2_env
690 (env, [], ety_env)
691 tyargs
692 nkinds
693 ~f:(fun (env, ty_errs, ety_env) x y ->
694 let ((env, ty_err_opt, ety_env), res) =
695 localize_targ_by_kind (env, ety_env) x y
697 let ty_errs =
698 Option.value_map ty_err_opt ~default:ty_errs ~f:(fun e ->
699 e :: ty_errs)
701 ((env, ty_errs, ety_env), res))
703 let ty_err_opt = Typing_error.multiple_opt ty_errs in
704 (* Note that we removed superfluous type arguments, because we don't have a kind to localize
705 them against.
706 It would also be useful to fill in Terr for missing type arguments, but this breaks some
707 checks on built-in collections that check the number of type arguments *after* localization. *)
708 ((env, ty_err_opt), tyl)
710 and localize_targ_by_kind (env, ety_env) ty (nkind : KindDefs.Simple.named_kind)
712 match (get_node ty, ety_env.wildcard_action) with
713 | (Twildcard, Wildcard_fresh_generic) ->
714 let r = get_reason ty in
715 let pos = get_pos ty in
716 let r = Typing_reason.localize r in
717 let (name, kind) = nkind in
718 let is_higher_kinded = KindDefs.Simple.get_arity kind > 0 in
719 if is_higher_kinded then
720 let (env, ty) = Env.fresh_type_error env Pos.none in
721 (* We don't support wildcards in place of HK type arguments *)
722 ((env, None, ety_env), ty)
723 else
724 let full_kind_without_bounds =
725 KindDefs.Simple.to_full_kind_without_bounds kind
727 let (env, new_name) =
728 (* add without bounds, because we need to substitute inside them first,
729 as done below *)
730 Env.add_fresh_generic_parameter_by_kind
733 (snd name)
734 full_kind_without_bounds
736 let ty_fresh = mk (r, Tgeneric (new_name, [])) in
737 (* Substitute fresh type parameters for original formals in constraint *)
738 let substs = SMap.add (snd name) ty_fresh ety_env.substs in
739 let ety_env = { ety_env with substs } in
740 let subst_and_add_localized_constraints env ck cstr_tys =
741 Typing_set.fold
742 (fun cstr_ty env ->
743 let cstr_ty = TIntegrity.Locl_Inst.instantiate substs cstr_ty in
744 TUtils.add_constraint env ck ty_fresh cstr_ty ety_env.on_error)
745 cstr_tys
748 let (env, ty_errs) =
749 match KindDefs.Simple.get_wilcard_bounds kind with
750 | KindDefs.Simple.NonLocalized decl_cstrs ->
751 List.fold_left
752 decl_cstrs
753 ~init:(env, [])
754 ~f:(fun (env, ty_errs) (ck, ty) ->
755 let ((env, ty_err_opt), ty) = localize ~ety_env env ty in
756 let ty_errs =
757 Option.value_map
758 ~default:ty_errs
759 ~f:(fun e -> e :: ty_errs)
760 ty_err_opt
762 let env =
763 TUtils.add_constraint env ck ty_fresh ty ety_env.on_error
765 (env, ty_errs))
766 | KindDefs.Simple.Localized { wc_lower; wc_upper } ->
767 let env =
768 subst_and_add_localized_constraints
770 Ast_defs.Constraint_as
771 wc_upper
773 let env =
774 subst_and_add_localized_constraints
776 Ast_defs.Constraint_super
777 wc_lower
779 (env, [])
781 let ty_err_opt = Typing_error.multiple_opt ty_errs in
782 ((env, ty_err_opt, ety_env), ty_fresh)
783 | _ ->
784 let ((env, ty_err_opt), ty) = localize_with_kind ~ety_env env ty nkind in
785 ((env, ty_err_opt, ety_env), ty)
787 and localize_class_instantiation
788 ~ety_env env r sid tyargs (class_info : _ option) =
789 let (pos, name) = sid in
790 match class_info with
791 | None ->
792 (* Without class info, we don't know the kinds of the arguments.
793 We assume they are non-HK types. *)
794 let (env, tyl) =
795 List.map_env_ty_err_opt
797 tyargs
798 ~f:(localize ~ety_env:{ ety_env with expand_visible_newtype = true })
799 ~combine_ty_errs:Typing_error.multiple_opt
801 (env, mk (r, Tclass (sid, nonexact, tyl)))
802 | Some class_info ->
803 if Option.is_some (Cls.enum_type class_info) then
804 let (ety_env, has_cycle) =
805 Typing_defs.add_type_expansion_check_cycles ety_env (pos, name)
807 match has_cycle with
808 | Some _ ->
809 let ty_err_opt =
810 Option.map
811 ety_env.on_error
813 Typing_error.(
814 fun on_error ->
815 apply_reasons ~on_error
816 @@ Secondary.Cyclic_enum_constraint pos)
818 let (env, ty) =
819 Env.fresh_type_error env (Pos_or_decl.unsafe_to_raw_pos pos)
821 ((env, ty_err_opt), ty)
822 | None ->
823 if Ast_defs.is_c_enum_class (Cls.kind class_info) then
824 (* Enum classes no longer has the ambiguity between the type of
825 * the enum set and the type of elements, so the enum class
826 * itself is seen as a Tclass
828 ((env, None), mk (r, Tclass (sid, nonexact, [])))
829 else
830 let (env, cstr) =
831 match Env.get_enum_constraint env name with
832 (* If not specified, default bound is arraykey *)
833 | Decl_entry.DoesNotExist
834 | Decl_entry.NotYetAvailable
835 | Decl_entry.Found None ->
836 ( (env, None),
837 MakeType.arraykey
838 (Reason.implicit_upper_bound (pos, "arraykey")) )
839 | Decl_entry.Found (Some ty) -> localize ~ety_env env ty
841 let enum_ty = mk (r, Tnewtype (name, [], cstr)) in
842 let r_dyn = r in
843 let enum_ty =
844 if ety_env.ish_weakening then
845 MakeType.intersection
846 r_dyn
847 [MakeType.locl_like r_dyn enum_ty; MakeType.arraykey r_dyn]
848 else
849 enum_ty
851 (env, enum_ty)
852 else
853 let tparams = Cls.tparams class_info in
854 let nkinds = KindDefs.Simple.named_kinds_of_decl_tparams tparams in
855 let ((env, err), tyl) =
856 localize_targs_by_kind
857 ~ety_env:{ ety_env with expand_visible_newtype = true }
859 tyargs
860 nkinds
862 (* Hide the class type if its internal and outside of the module *)
864 (not ety_env.make_internal_opaque)
865 || Typing_modules.is_class_visible env class_info
866 then
867 let r =
868 if TypecheckerOptions.using_extended_reasons env.genv.tcopt then
869 Typing_reason.(definition (Folded_class.pos class_info) r)
870 else
873 ((env, err), mk (r, Tclass (sid, nonexact, tyl)))
874 else
875 let callee_module =
876 match Cls.get_module class_info with
877 | Some m -> m
878 | None ->
879 failwith
880 "Internal error: module must exist for class to be not visible"
882 let new_r =
883 Reason.opaque_type_from_module (Cls.pos class_info, callee_module, r)
885 let cstr = MakeType.mixed new_r in
886 (* If the class supports dynamic, reveal this in the newtype *)
887 let cstr =
888 if Cls.get_support_dynamic_type class_info then
889 MakeType.supportdyn new_r cstr
890 else
891 cstr
893 ((env, err), mk (new_r, Tnewtype (name, tyl, cstr)))
895 and localize_typedef_instantiation
896 ~ety_env env (r : Reason.t) type_name tyargs (typedef_info : _ option) =
897 match typedef_info with
898 | Some typedef_info ->
899 let tparams = typedef_info.Typing_defs.td_tparams in
900 let nkinds = KindDefs.Simple.named_kinds_of_decl_tparams tparams in
901 let ((env, e1), tyargs) =
902 localize_targs_by_kind
903 ~ety_env:{ ety_env with expand_visible_newtype = true }
905 tyargs
906 nkinds
908 let ((env, e2), lty) =
909 TUtils.expand_typedef ety_env env r type_name tyargs
911 let ty_err_opt = Option.merge e1 e2 ~f:Typing_error.both in
912 ((env, ty_err_opt), lty)
913 | None ->
914 (* This must be unreachable. We only call localize_typedef_instantiation if we *know* that
915 we have a typedef with typedef info at hand. *)
916 failwith "Internal error: No info about typedef"
918 (* Localize a type with the given expected kind, which
919 may either indicate a higher-kinded or fully applied type.
921 and localize_with_kind
922 ~ety_env
924 (dty : decl_ty)
925 (expected_named_kind : KindDefs.Simple.named_kind) =
926 let expected_kind = snd expected_named_kind in
927 let (r, dty_) = deref dty in
928 let r = Typing_reason.localize r in
929 let arity = KindDefs.Simple.get_arity expected_kind in
930 if Int.( = ) arity 0 then
931 (* Not higher-kinded *)
932 localize ~ety_env env dty
933 else
934 match dty_ with
935 | Tapply (((_pos, name) as id), []) -> begin
936 match Env.get_class_or_typedef env name with
937 | Decl_entry.Found (Env.ClassResult class_info) ->
938 let tparams = Cls.tparams class_info in
939 let classish_kind =
940 KindDefs.Simple.type_with_params_to_simple_kind tparams
943 TIntegrity.Simple.is_subkind env ~sub:classish_kind ~sup:expected_kind
944 then
945 ((env, None), mk (r, Tclass (id, nonexact, [])))
946 else
947 let (env, ty) = Env.fresh_type_error env Pos.none in
948 ((env, None), ty)
949 | Decl_entry.Found (Env.TypedefResult typedef) ->
950 if Env.is_typedef_visible env ~name typedef then
951 ((env, None), mk (r, Tunapplied_alias name))
952 else
953 (* The bound is unused until the newtype is fully applied *)
954 let (env, ty) = Env.fresh_type_error env Pos.none in
955 ((env, None), mk (r, Tnewtype (name, [], ty)))
956 | Decl_entry.NotYetAvailable
957 | Decl_entry.DoesNotExist ->
958 (* We are expected to localize a higher-kinded type, but are given an unknown class name.
959 Not much we can do. *)
960 let (env, ty) = Env.fresh_type_error env Pos.none in
961 ((env, None), ty)
963 | Tgeneric (name, []) -> begin
964 match Env.get_pos_and_kind_of_generic env name with
965 | Some (_, gen_kind) ->
967 TIntegrity.Simple.is_subkind
969 ~sub:(KindDefs.Simple.from_full_kind gen_kind)
970 ~sup:expected_kind
971 then
972 ((env, None), mk (r, Tgeneric (name, [])))
973 else
974 let (env, ty) = Env.fresh_type_error env Pos.none in
975 ((env, None), ty)
976 | None ->
977 (* FIXME: Ideally, we would like to fail here, but sometimes we see type
978 parameters without an entry in the environment. *)
979 ((env, None), mk (r, Tgeneric (name, [])))
981 | Tgeneric (_, _targs)
982 | Tapply (_, _targs) ->
983 let (env, ty) = Env.fresh_type_error env Pos.none in
984 ((env, None), ty)
985 | Tany _ -> ((env, None), mk (r, make_tany ()))
986 | _dty_ ->
987 let (env, ty) = Env.fresh_type_error env Pos.none in
988 ((env, None), ty)
990 and localize_cstr_ty ~ety_env env ty tp_name =
991 let (env, ty) = localize ~ety_env env ty in
992 let ty =
993 map_reason ty ~f:(fun r ->
994 Reason.cstr_on_generics (Reason.to_pos r, tp_name))
996 (env, ty)
998 (* For the majority of cases when we localize a function type we instantiate
999 * the function's type parameters to Tvars. There are two cases where we do not do this.
1001 * 1) In Typing_subtype.subtype_method. See the comment for that function for why
1002 * this is necessary.
1003 * 2) When the type arguments are explicitly specified, in which case we instantiate
1004 * the type parameters to the provided types.
1006 and localize_ft
1007 ?(instantiation : method_instantiation option)
1008 ~ety_env
1009 ~def_pos
1011 (ft : decl_ty fun_type) =
1012 let ((env, arity_ty_err_opt), substs) =
1013 match instantiation with
1014 | Some { explicit_targs; use_name = _; use_pos } ->
1015 let ty_err_opt =
1017 (not (List.is_empty explicit_targs))
1018 && Int.( <> ) (List.length explicit_targs) (List.length ft.ft_tparams)
1019 then
1020 Some
1021 Typing_error.(
1022 primary
1023 @@ Primary.Expected_tparam
1025 decl_pos = def_pos;
1026 pos = use_pos;
1027 n = List.length ft.ft_tparams;
1029 else
1030 None
1032 let tvarl = List.map ~f:fst explicit_targs in
1033 let ft_subst = Subst.make_locl ft.ft_tparams tvarl in
1034 ((env, ty_err_opt), SMap.union ft_subst ety_env.substs)
1035 | None -> ((env, None), ety_env.substs)
1037 let ety_env = { ety_env with substs } in
1038 (* Localize the constraints for a type parameter declaration *)
1039 let rec localize_tparam ~nested env t =
1040 let ((env, e1), cstrl) =
1041 (* TODO(T70068435)
1042 For nested type parameters (i.e., type parameters of type parameters),
1043 we do not support constraints, yet. If nested type parameters do have
1044 constraints, this is reported earlier. We just throw them away here. *)
1045 if nested then
1046 ((env, None), [])
1047 else
1048 List.map_env_ty_err_opt
1050 t.tp_constraints
1051 ~combine_ty_errs:Typing_error.multiple_opt
1052 ~f:(fun env (ck, ty) ->
1053 let ((env, ty_err_opt), ty) =
1054 localize_cstr_ty ~ety_env env ty t.tp_name
1056 let name_str = snd t.tp_name in
1057 (* In order to access type constants on generics on where clauses,
1058 we need to add the constraints from the type parameters into the
1059 environment before localizing the where clauses with them. Temporarily
1060 add them to the environment here, and reset the environment later. *)
1061 let env =
1062 match ck with
1063 | Ast_defs.Constraint_as -> Env.add_upper_bound env name_str ty
1064 | Ast_defs.Constraint_super -> Env.add_lower_bound env name_str ty
1065 | Ast_defs.Constraint_eq ->
1066 Env.add_upper_bound
1067 (Env.add_lower_bound env name_str ty)
1068 name_str
1071 ((env, ty_err_opt), (ck, ty)))
1073 let ((env, e2), tparams) =
1074 List.map_env_ty_err_opt
1076 t.tp_tparams
1077 ~f:(localize_tparam ~nested:true)
1078 ~combine_ty_errs:Typing_error.multiple_opt
1080 let ty_err_opt = Option.merge e1 e2 ~f:Typing_error.both in
1081 ((env, ty_err_opt), { t with tp_constraints = cstrl; tp_tparams = tparams })
1083 let localize_where_constraint env (ty1, ck, ty2) =
1084 let ((env, e1), ty1) = localize ~ety_env env ty1 in
1085 let ((env, e2), ty2) = localize ~ety_env env ty2 in
1086 let ty_err_opt = Option.merge e1 e2 ~f:Typing_error.both in
1087 ((env, ty_err_opt), (ty1, ck, ty2))
1089 (* Grab and store the old tpenvs *)
1090 let old_tpenv = Env.get_tpenv env in
1091 let old_global_tpenv = env.tpenv in
1092 (* Always localize tparams so they are available for later Tast check *)
1093 let ((env, tparam_ty_err_opt), tparams) =
1094 List.map_env_ty_err_opt
1096 ft.ft_tparams
1097 ~f:(localize_tparam ~nested:false)
1098 ~combine_ty_errs:Typing_error.multiple_opt
1100 (* Localize the 'where' constraints *)
1101 let ((env, where_cstr_ty_err_opt), where_constraints) =
1102 List.map_env_ty_err_opt
1104 ft.ft_where_constraints
1105 ~f:localize_where_constraint
1106 ~combine_ty_errs:Typing_error.multiple_opt
1108 (* Remove the constraints we added for localizing where constraints *)
1109 let env = Env.env_with_tpenv env old_tpenv in
1110 let env = Env.env_with_global_tpenv env old_global_tpenv in
1111 (* If we're instantiating the generic parameters then add a deferred
1112 * check that constraints are satisfied under the
1113 * substitution [ety_env.substs].
1115 let (env, gen_param_ty_err_opt) =
1116 match instantiation with
1117 | Some { use_pos; _ } ->
1118 let (env, e1) =
1119 check_tparams_constraints ~use_pos ~ety_env env ft.ft_tparams
1121 let (env, e2) =
1122 check_where_constraints
1123 ~in_class:false
1124 ~use_pos
1125 ~definition_pos:def_pos
1126 ~ety_env
1128 ft.ft_where_constraints
1130 let ty_err_opt = Option.merge e1 e2 ~f:Typing_error.both in
1131 (env, ty_err_opt)
1132 | None -> (env, None)
1134 let (((env, _), variadic_params_ty_err_opt), params) =
1135 List.map_env_ty_err_opt
1136 (env, 0)
1137 ft.ft_params
1138 ~f:(fun (env, i) param ->
1139 let ((env, ty_err_opt), ty) = localize ~ety_env env param.fp_type in
1140 (((env, i + 1), ty_err_opt), { param with fp_type = ty }))
1141 ~combine_ty_errs:Typing_error.multiple_opt
1143 let ((env, implicit_params_ty_err_opt), implicit_params) =
1144 let (env, capability) =
1145 match ft.ft_implicit_params.capability with
1146 | CapTy c ->
1147 let (env, ty) = localize ~ety_env env c in
1148 (env, CapTy ty)
1149 | CapDefaults p -> ((env, None), CapDefaults p)
1151 (env, { capability })
1153 let ((env, ret_ty_err_opt), ret) = localize ~ety_env env ft.ft_ret in
1154 let ty_err_opt =
1155 Typing_error.multiple_opt
1156 @@ List.filter_map
1157 ~f:Fn.id
1159 arity_ty_err_opt;
1160 tparam_ty_err_opt;
1161 where_cstr_ty_err_opt;
1162 gen_param_ty_err_opt;
1163 variadic_params_ty_err_opt;
1164 implicit_params_ty_err_opt;
1165 ret_ty_err_opt;
1168 ( (env, ty_err_opt),
1170 ft with
1171 ft_params = params;
1172 ft_implicit_params = implicit_params;
1173 ft_ret = ret;
1174 ft_tparams = tparams;
1175 ft_where_constraints = where_constraints;
1178 (* Given a list of generic parameters [tparams] and a substitution
1179 * in [ety_env.substs] whose domain is at least these generic parameters,
1180 * check that the types satisfy
1181 * the constraints on the corresponding generic parameter.
1183 * Note that the constraints may contain occurrences of the generic
1184 * parameters, but the subsitution will be applied to them. e.g. if tparams is
1185 * <Tu as MyCovariant<Tu>, Tv super Tu>
1186 * and ety_env.substs is
1187 * Tu :-> C
1188 * Tv :-> I
1189 * with
1190 * class C extends MyContravariant<I> implements I { ... }
1191 * Then the constraints are satisfied, because
1192 * C is a subtype of MyContravariant<C>
1193 * I is a supertype of C
1195 and check_tparams_constraints ~use_pos ~ety_env env tparams =
1196 let check_tparam_constraints (env, ty_errs) t =
1197 match SMap.find_opt (snd t.tp_name) ety_env.substs with
1198 | Some ty ->
1199 List.fold_left
1200 t.tp_constraints
1201 ~init:(env, ty_errs)
1202 ~f:(fun (env, ty_errs) (ck, cstr_ty) ->
1203 let ((env, e1), cstr_ty) =
1204 localize_cstr_ty ~ety_env env cstr_ty t.tp_name
1206 Typing_log.(
1207 log_with_level env "generics" ~level:1 (fun () ->
1208 log_types
1209 (Pos_or_decl.of_raw_pos use_pos)
1212 Log_head
1213 ( "check_tparams_constraints: check_tparams_constraint",
1214 [Log_type ("cstr_ty", cstr_ty); Log_type ("ty", ty)] );
1215 ]));
1216 let (env, e2) =
1217 TGenConstraint.check_tparams_constraint env ~use_pos ck ~cstr_ty ty
1219 let ty_err_opt = Option.merge e1 e2 ~f:Typing_error.both in
1220 let ty_errs =
1221 Option.value_map
1222 ~default:ty_errs
1223 ~f:(fun e -> e :: ty_errs)
1224 ty_err_opt
1226 (env, ty_errs))
1227 | None -> (env, ty_errs)
1229 let (env, ty_errs) =
1230 List.fold_left tparams ~init:(env, []) ~f:check_tparam_constraints
1232 (env, Typing_error.multiple_opt ty_errs)
1234 and check_where_constraints
1235 ~in_class ~use_pos ~ety_env ~definition_pos env cstrl =
1236 let ety_env =
1237 let on_error =
1238 Some
1239 (Typing_error.Reasons_callback.explain_where_constraint
1240 use_pos
1241 ~in_class
1242 ~decl_pos:definition_pos)
1244 { ety_env with on_error }
1246 let (env, ty_errs) =
1247 List.fold_left
1248 cstrl
1249 ~init:(env, [])
1250 ~f:(fun (env, ty_errs) (ty, ck, cstr_ty) ->
1251 let ((env, e1), ty) = localize ~ety_env env ty in
1252 let ((env, e2), cstr_ty) = localize ~ety_env env cstr_ty in
1253 let (env, e3) =
1254 TGenConstraint.check_where_constraint
1255 ~in_class
1257 ~use_pos
1258 ~definition_pos
1260 ~cstr_ty
1263 let ty_err_opt =
1264 Typing_error.multiple_opt @@ List.filter_map ~f:Fn.id [e1; e2; e3]
1266 let ty_errs =
1267 Option.value_map
1268 ~default:ty_errs
1269 ~f:(fun e -> e :: ty_errs)
1270 ty_err_opt
1272 (env, ty_errs))
1274 (env, Typing_error.multiple_opt ty_errs)
1276 and localize_refinement ~ety_env env r root decl_cr =
1277 let mk_unsupported_err () =
1278 let pos = Reason.to_pos r in
1279 Option.map ety_env.on_error ~f:(fun on_error ->
1280 Typing_error.(
1281 apply_reasons ~on_error (Secondary.Unsupported_refinement pos)))
1283 let ((env, ty_err_opt), root) = localize ~ety_env env root in
1284 match get_node root with
1285 | Tclass (cid, Nonexact cr, tyl) ->
1286 let both_err e1 e2 = Option.merge e1 e2 ~f:Typing_error.both in
1287 let ((env, ty_err_opt), cr) =
1288 Class_refinement.fold_refined_consts
1289 ~f:(fun id { rc_bound; rc_is_ctx } ((env, ty_err_opt), cr) ->
1290 let ((env, ty_err_opt'), rc_bound) =
1291 match rc_bound with
1292 | TRexact ty ->
1293 let (env_err, ty) = localize ~ety_env env ty in
1294 (env_err, TRexact ty)
1295 | TRloose { tr_lower; tr_upper } ->
1296 let localize_list env tyl =
1297 List.map_env (env, None) tyl ~f:(fun (env, ty_err_opt) ty ->
1298 let ((env, ty_err_opt'), ty) = localize ~ety_env env ty in
1299 ((env, both_err ty_err_opt ty_err_opt'), ty))
1301 let ((env, ty_err_opt1), tr_lower) = localize_list env tr_lower in
1302 let ((env, ty_err_opt2), tr_upper) = localize_list env tr_upper in
1303 ( (env, both_err ty_err_opt1 ty_err_opt2),
1304 TRloose { tr_lower; tr_upper } )
1306 let cr =
1307 Class_refinement.add_refined_const id { rc_bound; rc_is_ctx } cr
1309 ((env, both_err ty_err_opt ty_err_opt'), cr))
1310 ~init:((env, ty_err_opt), cr)
1311 decl_cr
1313 ((env, ty_err_opt), mk (r, Tclass (cid, Nonexact cr, tyl)))
1314 | _ ->
1315 let (env, ty) = Env.fresh_type_error env Pos.none in
1316 ((env, mk_unsupported_err ()), ty)
1318 (* Like localize_no_subst, but uses the supplied kind, enabling support
1319 for higher-kinded types *)
1320 let localize_no_subst_and_kind env ~tparam ~on_error ty nkind =
1321 let ety_env =
1322 Option.value_map
1323 ~default:empty_expand_env
1324 ~f:empty_expand_env_with_on_error
1325 on_error
1327 let ety_env =
1328 match tparam with
1329 | Some tp
1330 when Attributes.mem SN.UserAttributes.uaExplicit tp.tp_user_attributes ->
1331 { ety_env with wildcard_action = Wildcard_require_explicit tp }
1332 | _ -> ety_env
1334 localize_with_kind ~ety_env env ty nkind
1336 (** Localize an explicit type argument to a constructor or function. We
1337 support the use of wildcards at the top level only *)
1338 let localize_targ_with_kind
1339 ?tparam ~check_well_kinded env hint (nkind : KindDefs.Simple.named_kind) =
1340 (* For explicit type arguments we support a wildcard syntax `_` for which
1341 * Hack will generate a fresh type variable *)
1342 let kind = snd nkind in
1343 match hint with
1344 | (p, Aast.Hwildcard) ->
1345 let is_higher_kinded = KindDefs.Simple.get_arity kind > 0 in
1346 if is_higher_kinded then
1347 let ty_err = Typing_error.(primary @@ Primary.HKT_wildcard (fst hint)) in
1348 let (env, ty) = Env.fresh_type_error env p in
1349 ((env, Some ty_err), (ty, hint))
1350 else
1351 let (env, ty) = Env.fresh_type env p in
1352 ((env, None), (ty, hint))
1353 | (hint_pos, _) ->
1354 let ty = Decl_hint.hint env.decl_env hint in
1355 let full_kind = KindDefs.Simple.to_full_kind_without_bounds kind in
1356 let in_non_reified_targ =
1357 Aast.is_erased full_kind.Typing_kinding_defs.reified
1359 if check_well_kinded then
1360 TIntegrity.Simple.check_well_kinded
1361 ~in_signature:false
1362 ~ignore_package_errors:in_non_reified_targ
1365 nkind;
1366 let (env, ty) =
1367 localize_no_subst_and_kind
1369 ~tparam
1370 ~on_error:
1371 (Some (Typing_error.Reasons_callback.invalid_type_hint hint_pos))
1373 nkind
1375 (env, (ty, hint))
1377 let localize_targ ?tparam ~check_well_kinded env hint =
1378 let named_kind =
1379 KindDefs.Simple.with_dummy_name (KindDefs.Simple.fully_applied_type ())
1381 localize_targ_with_kind ?tparam ~check_well_kinded env hint named_kind
1383 (* See signature in .mli file for details *)
1384 let localize_targs_with_kinds
1385 ~check_well_kinded
1386 ~is_method
1387 ~def_pos
1388 ~use_pos
1389 ~use_name
1390 ?(check_explicit_targs = true)
1391 ?(tparaml = [])
1393 named_kinds
1394 targl =
1395 let targ_count = List.length targl in
1396 let generated_tparam_count =
1397 List.count
1398 ~f:(fun t -> SN.Coeffects.is_generated_generic (snd t.tp_name))
1399 tparaml
1401 let tparam_count =
1402 match List.length tparaml with
1403 | 0 -> List.length named_kinds
1404 | n -> n
1406 let explicit_tparam_count = tparam_count - generated_tparam_count in
1408 let checking_rewritten_call () =
1409 (* Typing_phase expands the case of targl=[] to a list of wildcards matching the
1410 * length of tparaml, but some `if` condition checks retype already typed
1411 * expressions, so we get the generated list instead of what the user wrote
1412 * TODO(coeffects) attempt to remove Tast.to_nast_expr calls *)
1413 generated_tparam_count > 0
1414 && targ_count = tparam_count
1415 && List.for_all ~f:Aast_defs.is_wildcard_hint targl
1417 (* If there are explicit type arguments but too few or too many then
1418 * report an error *)
1419 let arity_ty_err_opt =
1422 Int.(
1423 targ_count = 0
1424 || targ_count = explicit_tparam_count
1425 || checking_rewritten_call ())
1426 then
1427 if is_method then
1428 Some
1429 Typing_error.(
1430 primary
1431 @@ Primary.Expected_tparam
1433 decl_pos = def_pos;
1434 pos = use_pos;
1435 n = explicit_tparam_count;
1437 else
1438 Some
1439 Typing_error.(
1440 primary
1441 @@ Primary.Type_arity_mismatch
1443 pos = use_pos;
1444 decl_pos = def_pos;
1445 expected = tparam_count;
1446 actual = targ_count;
1448 else
1449 None
1452 (* Declare and localize the explicit type arguments *)
1453 let (targ_tparaml, _) = List.zip_with_remainder targl tparaml in
1454 let ((env, ty_errs), explicit_targs) =
1455 List.map2_env
1456 (env, [])
1457 targ_tparaml
1458 (List.take named_kinds targ_count)
1459 ~f:(fun (env, ty_errs) (targ, tparam) y ->
1460 let ((env, ty_err_opt), res) =
1461 localize_targ_with_kind ~tparam ~check_well_kinded env targ y
1463 let ty_errs =
1464 Option.value_map ty_err_opt ~default:ty_errs ~f:(fun e ->
1465 e :: ty_errs)
1467 ((env, ty_errs), res))
1469 let explicit_targ_ty_err_opt = Typing_error.multiple_opt ty_errs in
1470 (* Generate fresh type variables for the remainder *)
1471 let ((env, implicit_targ_ty_err_opt), implicit_targs) =
1472 let mk_implicit_targ env (kind_name, kind) =
1473 let wildcard_hint = (use_pos, Aast.Hwildcard) in
1475 check_well_kinded
1476 && KindDefs.Simple.get_arity kind > 0
1477 && targ_count = 0
1478 then
1479 (* We only throw an error if the user didn't provide any type arguments at all.
1480 Otherwise, if they provided some, but not all of them, n arity mismatch
1481 triggers earlier in this function, independently from higher-kindedness *)
1482 let ty_err =
1483 Typing_error.(
1484 primary
1485 @@ Primary.HKT_implicit_argument
1487 pos = use_pos;
1488 decl_pos = fst kind_name;
1489 param_name = snd kind_name;
1492 let (env, ty) = Env.fresh_type_error env use_pos in
1493 ((env, Some ty_err), (ty, wildcard_hint))
1494 else
1495 let (env, tvar) =
1496 Env.fresh_type_reason
1498 use_pos
1499 (Reason.type_variable_generics (use_pos, snd kind_name, use_name))
1501 Typing_log.log_tparam_instantiation env use_pos (snd kind_name) tvar;
1502 ((env, None), (tvar, wildcard_hint))
1504 List.map_env_ty_err_opt
1506 (List.drop named_kinds targ_count)
1507 ~f:mk_implicit_targ
1508 ~combine_ty_errs:Typing_error.multiple_opt
1511 let check_for_explicit_user_attribute tparam (_, hint) =
1513 Attributes.mem SN.UserAttributes.uaExplicit tparam.tp_user_attributes
1514 && Aast_defs.is_wildcard_hint hint
1515 then
1516 let (decl_pos, param_name) = tparam.tp_name in
1517 Some
1518 Typing_error.(
1519 primary
1520 @@ Primary.Require_generic_explicit
1521 { decl_pos; param_name; pos = fst hint })
1522 else
1523 None
1526 let ua_ty_err_opt =
1527 if check_explicit_targs then
1528 Typing_error.multiple_opt
1529 @@ List.fold2_exn
1530 tparaml
1531 (explicit_targs @ implicit_targs)
1532 ~init:[]
1533 ~f:(fun ty_errs tp targ ->
1534 Option.value_map ~default:ty_errs ~f:(fun e -> e :: ty_errs)
1535 @@ check_for_explicit_user_attribute tp targ)
1536 else
1537 None
1539 let ty_err_opt =
1540 Typing_error.multiple_opt
1541 @@ List.filter_map
1542 ~f:Fn.id
1544 arity_ty_err_opt;
1545 explicit_targ_ty_err_opt;
1546 implicit_targ_ty_err_opt;
1547 ua_ty_err_opt;
1550 ((env, ty_err_opt), explicit_targs @ implicit_targs)
1552 let localize_targs
1553 ~check_well_kinded
1554 ~is_method
1555 ~def_pos
1556 ~use_pos
1557 ~use_name
1558 ?(check_explicit_targs = true)
1560 tparaml
1561 targl =
1562 let nkinds = KindDefs.Simple.named_kinds_of_decl_tparams tparaml in
1563 localize_targs_with_kinds
1564 ~check_well_kinded
1565 ~is_method
1566 ~def_pos
1567 ~use_pos
1568 ~use_name
1569 ~tparaml
1570 ~check_explicit_targs
1572 nkinds
1573 targl
1575 (* Performs no substitutions of generics and initializes Tthis to
1576 * Env.get_self env
1578 let localize_no_subst_
1579 env ~wildcard_action ~ish_weakening ~on_error ?report_cycle ty =
1580 let ety_env =
1582 empty_expand_env with
1583 type_expansions =
1584 Typing_defs.Type_expansions.empty_w_cycle_report ~report_cycle;
1585 on_error;
1586 wildcard_action;
1587 ish_weakening;
1590 localize env ty ~ety_env
1592 let localize_hint_no_subst env ~ignore_errors ?report_cycle h =
1593 let (pos, _) = h in
1594 let h = Decl_hint.hint env.decl_env h in
1595 localize_no_subst_
1597 ~on_error:
1598 (if ignore_errors then
1599 None
1600 else
1601 Some (Typing_error.Reasons_callback.invalid_type_hint pos))
1602 ~wildcard_action:Wildcard_illegal
1603 ~ish_weakening:false
1604 ?report_cycle
1607 let localize_hint_for_refinement env hint =
1608 let (pos, _) = hint in
1609 let h = Decl_hint.hint env.decl_env hint in
1610 let ((env, ty_err_opt), hint_ty) =
1611 localize_no_subst_
1613 ~on_error:(Some (Typing_error.Reasons_callback.invalid_type_hint pos))
1614 ~wildcard_action:Wildcard_fresh_generic
1615 ~ish_weakening:(Env.get_tcopt env |> TypecheckerOptions.pessimise_builtins)
1618 ((env, ty_err_opt), hint_ty)
1620 let localize_hint_for_lambda env h =
1621 let (pos, _) = h in
1622 let h = Decl_hint.hint env.decl_env h in
1623 localize_no_subst_
1625 ~on_error:(Some (Typing_error.Reasons_callback.invalid_type_hint pos))
1626 ~wildcard_action:Wildcard_fresh_tyvar
1627 ~ish_weakening:false
1630 let localize_no_subst env ~ignore_errors ty =
1631 localize_no_subst_
1633 ~on_error:
1634 (if ignore_errors then
1635 None
1636 else
1637 Some
1638 (Typing_error.Reasons_callback.invalid_type_hint
1639 (Pos_or_decl.unsafe_to_raw_pos @@ get_pos ty)))
1640 ~wildcard_action:Wildcard_illegal
1641 ~ish_weakening:false
1644 let localize_targs_and_check_constraints
1645 ~exact
1646 ~check_well_kinded
1647 ~def_pos
1648 ~use_pos
1649 ?(check_explicit_targs = true)
1651 class_id
1653 tparaml
1654 hintl =
1655 let ((env, e1), type_argl) =
1656 localize_targs
1657 ~check_well_kinded
1658 ~is_method:false
1659 ~def_pos
1660 ~use_pos
1661 ~use_name:(Utils.strip_ns (snd class_id))
1662 ~check_explicit_targs
1664 tparaml
1665 hintl
1667 let targs_tys = List.map ~f:fst type_argl in
1668 let this_ty =
1669 mk (r, Tclass (Positioned.of_raw_positioned class_id, exact, targs_tys))
1671 let ety_env =
1673 empty_expand_env with
1674 this_ty;
1675 substs = Subst.make_locl tparaml targs_tys;
1676 on_error = Some (Typing_error.Reasons_callback.unify_error_at use_pos);
1679 let (env, e2) = check_tparams_constraints ~use_pos ~ety_env env tparaml in
1680 let ty_err_opt = Option.merge e1 e2 ~f:Typing_error.both in
1681 ((env, ty_err_opt), this_ty, type_argl)
1683 (* Add generic parameters to the environment, localize their bounds, and
1684 * transform these into a flat list of constraints of the form (ty1,ck,ty2)
1685 * where ck is as, super or =
1687 let localize_and_add_generic_parameters_with_bounds
1688 ~ety_env (env : env) (tparams : decl_tparam list) =
1689 let env = Env.add_generic_parameters env tparams in
1690 let localize_bound
1691 env ({ tp_name = (pos, name); tp_constraints = cstrl; _ } : decl_tparam) =
1692 (* TODO(T70068435) This may have to be touched when adding support for constraints on HK
1693 types *)
1694 let tparam_ty = mk (Reason.witness_from_decl pos, Tgeneric (name, [])) in
1695 List.map_env_ty_err_opt
1697 cstrl
1698 ~f:(fun env (ck, cstr) ->
1699 let (env, ty) = localize env cstr ~ety_env in
1700 (env, (tparam_ty, ck, ty)))
1701 ~combine_ty_errs:Typing_error.multiple_opt
1703 let ((env, ty_err_opt), cstrss) =
1704 List.map_env_ty_err_opt
1706 tparams
1707 ~f:localize_bound
1708 ~combine_ty_errs:Typing_error.multiple_opt
1710 let add_constraint env (ty1, ck, ty2) =
1711 TUtils.add_constraint env ck ty1 ty2 ety_env.on_error
1713 let env = List.fold_left (List.concat cstrss) ~f:add_constraint ~init:env in
1714 (env, ty_err_opt)
1716 let localize_and_add_where_constraints ~ety_env (env : env) where_constraints =
1717 let localize_and_add_constraint (env, ty_errs) (ty1, ck, ty2) =
1718 let ((env, e1), ty1) = localize env ty1 ~ety_env in
1719 let ((env, e2), ty2) = localize env ty2 ~ety_env in
1720 let env = TUtils.add_constraint env ck ty1 ty2 ety_env.on_error in
1721 let ty_errs =
1722 Option.(
1723 value_map ~default:ty_errs ~f:(fun e -> e :: ty_errs)
1724 @@ merge e1 e2 ~f:Typing_error.both)
1726 (env, ty_errs)
1728 let (env, ty_errs) =
1729 List.fold_left
1730 where_constraints
1731 ~f:localize_and_add_constraint
1732 ~init:(env, [])
1734 (env, Typing_error.multiple_opt ty_errs)
1736 (* Helper functions *)
1738 let sub_type_decl env ty1 ty2 on_error =
1739 let ((env, e1), ty1) = localize_no_subst env ~ignore_errors:true ty1 in
1740 let ((env, e2), ty2) = localize_no_subst env ~ignore_errors:true ty2 in
1741 let (env, e3) = TUtils.sub_type env ty1 ty2 on_error in
1742 let ty_err_opt =
1743 Typing_error.multiple_opt @@ List.filter_map ~f:Fn.id [e1; e2; e3]
1745 (env, ty_err_opt)
1747 let is_sub_type_decl ?coerce env ty1 ty2 =
1748 let ((env, e1), ty1) = localize_no_subst env ~ignore_errors:true ty1 in
1749 let ((env, e2), ty2) = localize_no_subst env ~ignore_errors:true ty2 in
1750 let (_env, e3) =
1751 TUtils.sub_type
1752 ?coerce
1756 (Some (Typing_error.Reasons_callback.unify_error_at Pos.none))
1758 Option.is_none e1 && Option.is_none e2 && Option.is_none e3
1760 let localize_and_add_generic_parameters_and_where_constraints
1761 ~ety_env env tparams where_constraints =
1762 let (env, e1) =
1763 localize_and_add_generic_parameters_with_bounds env tparams ~ety_env
1765 let (env, e2) =
1766 localize_and_add_where_constraints env where_constraints ~ety_env
1768 (env, Option.merge e1 e2 ~f:Typing_error.both)
1770 let localize_and_add_ast_generic_parameters_and_where_constraints
1772 ~ignore_errors
1773 (tparams : Nast.tparam list)
1774 (where_constraints : Aast_defs.where_constraint_hint list) =
1775 let tparams : decl_tparam list =
1776 List.map tparams ~f:(Decl_hint.aast_tparam_to_decl_tparam env.decl_env)
1778 let where_constraints : decl_where_constraint list =
1779 List.map where_constraints ~f:(fun (h1, ck, h2) ->
1780 (Decl_hint.hint env.decl_env h1, ck, Decl_hint.hint env.decl_env h2))
1782 let ety_env =
1783 if ignore_errors then
1784 empty_expand_env
1785 else
1786 empty_expand_env_with_on_error
1787 (Env.invalid_type_hint_assert_primary_pos_in_current_decl env)
1789 localize_and_add_generic_parameters_and_where_constraints
1790 ~ety_env
1792 tparams
1793 where_constraints
1795 let () = TUtils.localize_no_subst_ref := localize_no_subst
1797 let () = TUtils.localize_ref := localize