src/typing/annotation_inference.ml (1,215 lines of code) (raw):

(* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. *) open Reason open Subst open Type open Type.AConstraint open TypeUtil let object_like_op = function | Annot_SpecializeT _ | Annot_ThisSpecializeT _ | Annot_UseT_TypeT _ | Annot_CJSRequireT _ | Annot_ImportTypeT _ | Annot_ImportTypeofT _ | Annot_ImportNamedT _ | Annot_ImportDefaultT _ | Annot_ImportModuleNsT _ | Annot_CJSExtractNamedExportsT _ | Annot_ExportNamedT _ | Annot_ExportTypeT _ | Annot_AssertExportIsTypeT _ | Annot_CopyNamedExportsT _ | Annot_CopyTypeExportsT _ | Annot_ElemT _ | Annot_GetStaticsT _ | Annot_MakeExactT _ | Annot_MixinT _ | Annot_ObjKitT _ | Annot_ObjTestProtoT _ | Annot_UnaryMinusT _ | Annot_NotT _ | Annot_ObjKeyMirror _ | Annot_ObjMapConst _ | Annot_GetKeysT _ | Annot_ToStringT _ | Annot__Future_added_value__ _ -> false | Annot_GetPropT _ | Annot_GetElemT _ | Annot_LookupT _ | Annot_ObjRestT _ | Annot_GetValuesT _ -> true let primitive_promoting_op = function | Annot_GetPropT _ | Annot_GetElemT _ | Annot_LookupT _ -> true (* TODO: enumerate all use types *) | _ -> false let function_like_op op = object_like_op op let get_fully_resolved_type cx id = let (_, node) = Context.find_root cx id in match node.Constraint.constraints with | Constraint.FullyResolved (_, (lazy t)) -> t | Constraint.Resolved _ | Constraint.Unresolved _ -> failwith "unexpected unresolved constraint in annotation inference" let get_builtin_typeapp cx reason x targs = let t = Flow_js_utils.lookup_builtin_strict cx x reason in TypeUtil.typeapp reason t targs module type S = sig val unresolved_tvar : Context.t -> Reason.t -> int val mk_typeof_annotation : Context.t -> ?trace:Type.trace -> Reason.t -> Type.t -> Type.t val mk_type_reference : Context.t -> Reason.t -> Type.t -> Type.t val get_prop : Context.t -> Type.use_op -> Reason.t -> Reason.name -> Type.t -> Type.t val get_elem : Context.t -> Type.use_op -> Reason.t -> key:Type.t -> Type.t -> Type.t val qualify_type : Context.t -> Type.use_op -> Reason.t -> Reason.t * Reason.name -> Type.t -> Type.t val assert_export_is_type : Context.t -> Reason.t -> string -> Type.t -> Type.t val resolve_id : Context.t -> Type.ident -> Type.t -> unit val mk_sig_tvar : Context.t -> Reason.t -> Type.t Lazy.t -> Type.t val cjs_require : Context.t -> Type.t -> Reason.t -> bool -> Type.t val export_named : Context.t -> Reason.reason -> Type.export_kind -> (ALoc.t option * Type.t) NameUtils.Map.t -> Type.t -> Type.t val cjs_extract_named_exports : Context.t -> Reason.reason -> Reason.reason * Type.exporttypes * bool -> Type.t -> Type.t val import_default : Context.t -> Reason.t -> Type.import_kind -> string -> string -> bool -> Type.t -> Type.t val import_named : Context.t -> Reason.t -> Type.import_kind -> string -> string -> bool -> Type.t -> Type.t val import_ns : Context.t -> Reason.t -> bool -> Type.t -> Type.t val import_typeof : Context.t -> Reason.t -> string -> Type.t -> Type.t val specialize : Context.t -> Type.t -> Type.use_op -> Reason.t -> Reason.t -> Type.t list Base.Option.t -> Type.t val copy_named_exports : Context.t -> from_ns:Type.t -> Reason.t -> module_t:Type.t -> Type.t val copy_type_exports : Context.t -> from_ns:Type.t -> Reason.t -> module_t:Type.t -> Type.t val unary_minus : Context.t -> Reason.t -> Type.t -> Type.t val unary_not : Context.t -> Reason.t -> Type.t -> Type.t val mixin : Context.t -> Reason.t -> Type.t -> Type.t val object_spread : Context.t -> Type.use_op -> Reason.reason -> Type.Object.Spread.target -> Type.Object.Spread.state -> Type.t -> Type.t val obj_test_proto : Context.t -> Reason.t -> Type.t -> Type.t val obj_rest : Context.t -> Reason.t -> string list -> Type.t -> Type.t val arr_rest : Context.t -> Type.use_op -> Reason.t -> int -> Type.t -> Type.t val set_dst_cx : Context.t -> unit val elab_t : Context.t -> ?seen:ISet.t -> Type.t -> Type.AConstraint.op -> Type.t end module rec ConsGen : S = struct (* Annotation inference is performed in the context of the definition module (this * is what the input `cx` in elab_t etc. represents). However, in order to be * able to raise errors during annotation inference, we need to have access to the * destination context. This is what this reference is for. `dst_cx_ref` is set * Check_serivce.mk_check_file once per file right after the destination context * is created. *) let dst_cx_ref = ref None let set_dst_cx cx = dst_cx_ref := Some cx (* Errors created with [error_unsupported] are actually reported. Compare this to * errors created with Flow_js_utils.add_output which are recorded in the context * of the source of the annotations, and are therefore ignored. This function checks * that dst_cx_ref has been set and uses that as the target context. * * The only kind of errors that are reported here are "unsupported" cases. These * are mostly cases that rely on subtyping, which is not implemented here; most * commonly evaluating call-like EvalTs and speculation. *) let error_unsupported_reason ?suggestion cx t reason_op = let loc = Reason.aloc_of_reason reason_op in let msg = Error_message.EAnnotationInference (loc, reason_op, TypeUtil.reason_of_t t, suggestion) in (match !dst_cx_ref with | None -> assert false | Some dst_cx -> Flow_js_utils.add_annot_inference_error ~src_cx:cx ~dst_cx msg); AnyT.error reason_op let error_unsupported ?suggestion cx t op = let reason_op = AConstraint.display_reason_of_op op in error_unsupported_reason ?suggestion cx t reason_op let error_recursive cx reason = let loc = Reason.aloc_of_reason reason in let msg = Error_message.EAnnotationInferenceRecursive (loc, reason) in (match !dst_cx_ref with | None -> assert false | Some dst_cx -> Flow_js_utils.add_annot_inference_error ~src_cx:cx ~dst_cx msg); AnyT.error reason let error_internal_reason cx msg reason_op = let loc = Reason.aloc_of_reason reason_op in let msg = Error_message.(EInternal (loc, UnexpectedAnnotationInference msg)) in (match !dst_cx_ref with | None -> assert false | Some dst_cx -> Flow_js_utils.add_annot_inference_error ~src_cx:cx ~dst_cx msg); AnyT.error reason_op let error_internal cx msg op = let reason_op = AConstraint.display_reason_of_op op in error_internal_reason cx msg reason_op let dummy_trace = Trace.dummy_trace (* Repositioning does not seem to have any perceptible impact in annotation * inference. Instead of replicating the convoluted implementation of Flow_js * here, we just return the same type intact. *) let reposition _cx _loc t = t (*****************) (* Instantiation *) (*****************) module Instantiation_helper = struct let cache_instantiate _cx _trace ~use_op:_ ?cache:_ _typeparam _reason_op _reason_tapp t = t (* We will not be solving implicit instantiation problems here. The only case * where we will need to use this function is when a PolyT needs to be used * as a monomorphic type. In this case, the only sensible thing to do is to * use the bound of each parameter as the argument to the intantiation. *) let mk_targ _cx typeparam _reason_op _reason_tapp = typeparam.Type.bound let is_subtype _cx _trace ~use_op:_ (_t1, _t2) = () let reposition cx ?trace:_ loc ?desc:_ ?annot_loc:_ t = reposition cx loc t let unresolved_id = Avar.unresolved let resolve_id cx _trace ~use_op:_ (_, id) t = ConsGen.resolve_id cx id t end module InstantiationKit = Flow_js_utils.Instantiation_kit (Instantiation_helper) let instantiate_poly cx = InstantiationKit.instantiate_poly cx dummy_trace let mk_typeapp_of_poly cx = InstantiationKit.mk_typeapp_of_poly cx dummy_trace let fix_this_class cx = InstantiationKit.fix_this_class cx dummy_trace (***********) (* Imports *) (***********) module Import_export_helper = struct type r = Type.t let reposition cx ?trace:_ loc ?desc:_ ?annot_loc:_ t = reposition cx loc t let return _cx ~use_op:_ _trace t = t let import_type cx _ reason export_name t = ConsGen.elab_t cx t (Annot_ImportTypeT (reason, export_name)) let import_typeof cx _trace reason export_name t = ConsGen.import_typeof cx reason export_name t let export_named cx _trace (reason, named, kind) t = ConsGen.export_named cx reason kind named t let export_named_fresh_var = export_named let export_type cx _trace (reason, export_name, target_module_t) export_t = ConsGen.elab_t cx export_t (Annot_ExportTypeT (reason, export_name, target_module_t)) let cjs_extract_named_exports cx _ (reason, local_module) t = ConsGen.cjs_extract_named_exports cx reason local_module t (* This check is bypassed in annotation inference *) let assert_import_is_value _cx _trace _reason _name _export_t = () let error_type = AnyT.error let fix_this_class = InstantiationKit.fix_this_class let mk_typeof_annotation = ConsGen.mk_typeof_annotation end module CJSRequireTKit = Flow_js_utils.CJSRequireT_kit (Import_export_helper) module ImportModuleNsTKit = Flow_js_utils.ImportModuleNsT_kit (Import_export_helper) module ImportDefaultTKit = Flow_js_utils.ImportDefaultT_kit (Import_export_helper) module ImportNamedTKit = Flow_js_utils.ImportNamedT_kit (Import_export_helper) module ImportTypeTKit = Flow_js_utils.ImportTypeT_kit (Import_export_helper) module ImportTypeofTKit = Flow_js_utils.ImportTypeofT_kit (Import_export_helper) module ExportNamedTKit = Flow_js_utils.ExportNamedT_kit (Import_export_helper) module AssertExportIsTypeTKit = Flow_js_utils.AssertExportIsTypeT_kit (Import_export_helper) module CopyNamedExportsTKit = Flow_js_utils.CopyNamedExportsT_kit (Import_export_helper) module CopyTypeExportsTKit = Flow_js_utils.CopyTypeExportsT_kit (Import_export_helper) module ExportTypeTKit = Flow_js_utils.ExportTypeT_kit (Import_export_helper) module CJSExtractNamedExportsTKit = Flow_js_utils.CJSExtractNamedExportsT_kit (Import_export_helper) (***********) (* GetProp *) (***********) module Get_prop_helper = struct type r = Type.t let perform_read_prop_action cx use_op propref p ureason = match Property.read_t p with | Some t -> reposition cx (aloc_of_reason ureason) t | None -> let (reason_prop, prop_name) = match propref with | Named (r, x) -> (r, Some x) | Computed t -> (reason_of_t t, None) in let msg = Error_message.EPropNotReadable { reason_prop; prop_name; use_op } in Flow_js_utils.add_output cx msg; AnyT.error ureason let cg_lookup_ cx use_op t reason_op propref = ConsGen.elab_t cx t (Annot_LookupT (reason_op, use_op, propref)) let read_prop cx _trace options reason_prop reason_op l _super x pmap = let { Flow_js_utils.Access_prop_options.use_op; _ } = options in let propref = Named (reason_prop, x) in match NameUtils.Map.find_opt x pmap with | Some p -> perform_read_prop_action cx use_op propref p reason_op | None -> let l = (* munge names beginning with single _ *) if Flow_js_utils.is_munged_prop_name cx x then ObjProtoT (reason_of_t l) else l in cg_lookup_ cx use_op l reason_op propref let error_type = AnyT.error (* We could have just returned `t` here. The OpenT indirection is for compatibility * with Flow_js. Specifically, without the OpenT the transformation in * https://github.com/facebook/flow/blob/8c3825a1be188e9ade4ad4ed515361bb28c65d8a/src/typing/flow_js.ml#L1744-L1755 * would fire, causing a divergence in the behavior of this module and Flow_js. *) let return cx ~use_op _trace t = match t with | OpenT _ -> t | _ -> Tvar.mk_fully_resolved cx use_op (reason_of_t t) t (* We will not be doing subtyping checks in annotation inference. *) let dict_read_check _ _ ~use_op:_ _ = () let reposition cx ?trace:_ loc ?desc:_ ?annot_loc:_ t = reposition cx loc t let enum_proto cx _trace ~reason (enum_reason, trust, enum) = let enum_t = DefT (enum_reason, trust, EnumT enum) in let { representation_t; _ } = enum in get_builtin_typeapp cx reason (OrdinaryName "$EnumProto") [enum_t; representation_t] let cg_lookup cx _trace ~obj_t:_ t (reason_op, _kind, propref, use_op, _ids) = cg_lookup_ cx use_op t reason_op propref let cg_get_prop cx _trace t (use_op, access_reason, _, (prop_reason, name)) = ConsGen.elab_t cx t (Annot_GetPropT (access_reason, use_op, Named (prop_reason, name))) end module GetPropTKit = Flow_js_utils.GetPropT_kit (Get_prop_helper) let unresolved_tvar cx reason = Avar.unresolved cx reason (** [ensure_annot_resolved cx reason id] ensures that the annotation constraint * associated with [id] has been resolved. If the respective constraint is already * resolved then it returns immediately. Otherwise, it resolves [id] immediately * to the 'any' type. In the case of an [Anno_op (_, _, dep_id)] constraint we also * update the "dependents" set of [dep_id], so that we don't attempt to resolve * [id] once again when [dep_id] gets resolved. *) let rec ensure_annot_resolved cx reason id = let module A = Type.AConstraint in match Context.find_avar cx id with | (_, { A.constraints = A.Annot_resolved; _ }) -> get_fully_resolved_type cx id | (_, { A.constraints = A.Annot_unresolved _; _ }) -> let t = error_recursive cx reason in resolve_id cx id t; t | (root_id, { A.constraints = A.Annot_op { id = dep_id; _ }; _ }) -> let (_, { A.constraints = dep_constraint; _ }) = Context.find_avar cx dep_id in A.update_deps_of_constraint dep_constraint ~f:(fun deps -> ISet.filter (fun id2 -> let (root_id2, _) = Context.find_avar cx id2 in root_id <> root_id2) deps ); let t = error_recursive cx reason in resolve_id cx id t; t and mk_lazy_tvar cx reason f = let id = Reason.mk_id () in let tvar = OpenT (reason, id) in let t = lazy ( Avar.unresolved_with_id cx id reason; f id; (* Before forcing the type constraint of [id] we need to make sure the * respective annotation constraint has been processed. If not we infer * the empty type. *) ensure_annot_resolved cx reason id ) in let constraints = Constraint.FullyResolved (unknown_use, t) in Context.add_tvar cx id (Constraint.Root { Constraint.rank = 0; constraints }); tvar and mk_sig_tvar cx reason (resolved : Type.t Lazy.t) = let f id = let t = Lazy.force resolved in resolve_id cx id t in mk_lazy_tvar cx reason f (** [resolve_id cx id1 t] resolves an annotation tvar [id1] to a type [t] * * - If [t] is a concrete type, we mark [id1] as a resolved annotation tvar and * record it as fully resolved in the type graph. * * - If [t] is an OpenT (_, id2), then we unify [id1] and [id2]. (See merge_ids.) *) and resolve_id cx id t = let module A = Type.AConstraint in let module C = Type.Constraint in match t with | Type.OpenT (_, id2) -> merge_ids cx id id2 | _ -> let (root_id1, root1) = Context.find_avar cx id in Context.add_avar cx root_id1 A.fully_resolved_node; Context.add_tvar cx root_id1 (C.fully_resolved_node t); let dependents1 = deps_of_constraint root1.A.constraints in resolve_dependent_set cx dependents1 t (** Makes id1 a goto node to id2. It also appends depndents of id1 to those of id2. * If id2 is a resolved node, then dependents can be immediately resolved using * the resolved type of id2. *) and goto cx id1 dependents1 (id2, root2) = let module A = Type.AConstraint in let module T = Type.Constraint in Context.add_tvar cx id1 (T.Goto id2); Context.add_avar cx id1 (A.Goto id2); match root2.A.constraints with | (A.Annot_op _ | A.Annot_unresolved _) as constraint_ -> update_deps_of_constraint ~f:(ISet.union dependents1) constraint_ | A.Annot_resolved -> let t = get_fully_resolved_type cx id2 in resolve_dependent_set cx dependents1 t (** Similar to Flow_js.merge_ids. Uses rank information to determine which one * of [id1] and [id2] will become the goto node and which one the root. *) and merge_ids cx id1 id2 = let module A = Type.AConstraint in let ((id1, root1), (id2, root2)) = (Context.find_avar cx id1, Context.find_avar cx id2) in if id1 = id2 then () else if root1.A.rank < root2.A.rank then let deps1 = deps_of_constraint root1.A.constraints in goto cx id1 deps1 (id2, root2) else if root2.A.rank < root1.A.rank then let deps2 = deps_of_constraint root2.A.constraints in goto cx id2 deps2 (id1, root1) else ( Context.add_avar cx id2 (A.Root { root2 with A.rank = root1.A.rank + 1 }); let deps1 = deps_of_constraint root1.A.constraints in goto cx id1 deps1 (id2, root2) ) and resolve_dependent_set cx dependents t = Context.iter_annot_dependent_set cx (fun id op -> resolve_id cx id (elab_t cx t op)) dependents and elab_open cx ~seen reason id op = if ISet.mem id seen then error_recursive cx reason else let module A = Type.AConstraint in let (_, { A.constraints; _ }) = Context.find_avar cx id in match constraints with | A.Annot_resolved -> (* [id] may refer to a lazily resolved constraint (e.g. created through * [mk_lazy_tvar]). To protect against trying to force recursive lazy * structures, we introduce a lazy indirection around the resulting * constraint. An example that would have cause this unwanted behavior is * * declare var x: { * p: number; * q: typeof (x.p); * }; * * This lazy indirection allows the type of `x` to be resolved, before we * attempt to force the constraint for `x.p`. *) let resolved = lazy ((* Annot_resolved ids definitelly appear in the type graph *) let t = get_fully_resolved_type cx id in elab_t cx ~seen:(ISet.add id seen) t op ) in mk_sig_tvar cx (AConstraint.reason_of_op op) resolved | A.Annot_unresolved _ | A.Annot_op _ -> let fresh_id = Avar.constrained cx op id in OpenT (reason, fresh_id) and elab_t cx ?(seen = ISet.empty) t op = match (t, op) with | (EvalT (t, TypeDestructorT (use_op, reason, ReadOnlyType), _), _) -> let t = make_readonly cx use_op reason t in elab_t cx t op | (EvalT (t, TypeDestructorT (use_op, reason, SpreadType (target, todo_rev, head_slice)), _), _) -> let state = Object.( Spread. { todo_rev; acc = Base.Option.value_map ~f:(fun x -> [InlineSlice x]) ~default:[] head_slice; spread_id = Reason.mk_id (); union_reason = None; curr_resolve_idx = 0; } ) in let t = object_spread cx use_op reason target state t in elab_t cx t op | (EvalT (t, TypeDestructorT (use_op, reason, RestType (options, r)), _), _) -> let state = Object.Rest.One r in let t = object_rest cx use_op reason options state t in elab_t cx t op | (EvalT (t, TypeDestructorT (_, reason, TypeMap ObjectKeyMirror), _), _) -> let t = elab_t cx t (Annot_ObjKeyMirror reason) in elab_t cx t op | (EvalT (t, TypeDestructorT (_, reason, TypeMap (ObjectMapConst t')), _), _) -> let t = elab_t cx t (Annot_ObjMapConst (reason, t')) in elab_t cx t op | (EvalT (t, TypeDestructorT (_, reason, ValuesType), _), _) -> let t = elab_t cx t (Annot_GetValuesT reason) in elab_t cx t op | (EvalT (_, TypeDestructorT (_, _, TypeMap (ObjectMap _)), _), _) -> error_unsupported ~suggestion:"$ObjMapConst" cx t op | (EvalT (_, TypeDestructorT (_, _, TypeMap (ObjectMapi _)), _), _) -> error_unsupported ~suggestion:"$KeyMirror" cx t op | (EvalT _, _) -> error_unsupported cx t op | (OpenT (reason, id), _) -> elab_open cx ~seen reason id op | (TypeDestructorTriggerT _, _) | (InternalT _, _) -> error_unsupported cx t op | (AnnotT (r, t, _), _) -> let t = reposition cx (aloc_of_reason r) t in elab_t cx ~seen t op (*********************************************************************) (* UseT TypeT (runtime types derive static types through annotation) *) (*********************************************************************) (* First handle catch-all cases of subtyping_kit.ml *) | ((MaybeT _ | OptionalT _), Annot_UseT_TypeT _) -> error_unsupported cx t op | (ThisTypeAppT (reason_tapp, c, this, ts), Annot_UseT_TypeT _) -> let reason_op = Type.AConstraint.reason_of_op op in let tc = specialize_class cx c reason_op reason_tapp ts in let t = this_specialize cx reason_tapp this tc in elab_t cx t op | (TypeAppT (reason_tapp, typeapp_use_op, c, ts), Annot_UseT_TypeT _) -> (* NOTE omitting TypeAppExpansion.push_unless_loop check. *) let reason_op = Type.AConstraint.reason_of_op op in let t = mk_typeapp_instance cx ~use_op:typeapp_use_op ~reason_op ~reason_tapp c ts in elab_t cx t op | (DefT (reason_tapp, _, PolyT { tparams_loc; tparams = ids; _ }), Annot_UseT_TypeT reason) -> Flow_js_utils.add_output cx (Error_message.EMissingTypeArgs { reason_op = reason; reason_tapp; reason_arity = Flow_js_utils.mk_poly_arity_reason tparams_loc; min_arity = Flow_js_utils.poly_minimum_arity ids; max_arity = Nel.length ids; } ); AnyT.error reason | (ThisClassT (r, i, is_this, this_name), Annot_UseT_TypeT reason) -> let c = fix_this_class cx reason (r, i, is_this, this_name) in elab_t cx c op | (DefT (_, _, ClassT it), Annot_UseT_TypeT reason) -> (* a class value annotation becomes the instance type *) reposition cx (aloc_of_reason reason) it | (DefT (_, _, TypeT (_, l)), Annot_UseT_TypeT _) -> l | (DefT (lreason, trust, EnumObjectT enum), Annot_UseT_TypeT _) -> (* an enum object value annotation becomes the enum type *) mk_enum_type ~trust lreason enum | (DefT (enum_reason, _, EnumT _), Annot_UseT_TypeT reason) -> Flow_js_utils.add_output cx Error_message.(EEnumMemberUsedAsType { reason; enum_reason }); AnyT.error reason | (l, Annot_UseT_TypeT reason_use) -> (match l with (* Short-circut as we already error on the unresolved name. *) | AnyT (_, AnyError (Some UnresolvedName)) -> () | AnyT _ -> Flow_js_utils.add_output cx Error_message.(EAnyValueUsedAsType { reason_use }) | _ -> Flow_js_utils.add_output cx Error_message.(EValueUsedAsType { reason_use })); AnyT.error reason_use (*****************) (* `import type` *) (*****************) | (_, Annot_ImportTypeT (reason, export_name)) -> ImportTypeTKit.on_concrete_type cx dummy_trace reason export_name t (*******************) (* `import typeof` *) (*******************) | (_, Annot_ImportTypeofT (reason, export_name)) -> ImportTypeofTKit.on_concrete_type cx dummy_trace reason export_name t (******************) (* Module exports *) (******************) | (ModuleT m, Annot_ExportNamedT (reason, tmap, export_kind)) -> ExportNamedTKit.on_ModuleT cx dummy_trace (reason, tmap, export_kind) t m | (_, Annot_AssertExportIsTypeT (_, name)) -> AssertExportIsTypeTKit.on_concrete_type cx dummy_trace name t | (ModuleT m, Annot_CopyNamedExportsT (reason, target_module_t)) -> CopyNamedExportsTKit.on_ModuleT cx dummy_trace (reason, target_module_t) m | (ModuleT m, Annot_CopyTypeExportsT (reason, target_module_t)) -> CopyTypeExportsTKit.on_ModuleT cx dummy_trace (reason, target_module_t) m | (_, Annot_ExportTypeT (reason, export_name, target_module_t)) -> ExportTypeTKit.on_concrete_type cx dummy_trace (reason, export_name, target_module_t) t | (AnyT (lreason, _), Annot_CopyNamedExportsT (reason, target_module)) -> CopyNamedExportsTKit.on_AnyT cx dummy_trace lreason (reason, target_module) | (AnyT (lreason, _), Annot_CopyTypeExportsT (reason, target_module)) -> CopyTypeExportsTKit.on_AnyT cx dummy_trace lreason (reason, target_module) | (_, Annot_CJSExtractNamedExportsT (reason, local_module)) -> CJSExtractNamedExportsTKit.on_concrete_type cx dummy_trace (reason, local_module) t (******************) (* Module imports *) (******************) | (ModuleT m, Annot_CJSRequireT (reason, is_strict)) -> CJSRequireTKit.on_ModuleT cx dummy_trace (reason, is_strict) m | (ModuleT m, Annot_ImportModuleNsT (reason, is_strict)) -> ImportModuleNsTKit.on_ModuleT cx dummy_trace (reason, is_strict) m | (ModuleT m, Annot_ImportDefaultT (reason, import_kind, local, is_strict)) -> ImportDefaultTKit.on_ModuleT cx dummy_trace (reason, import_kind, local, is_strict) m | (ModuleT m, Annot_ImportNamedT (reason, import_kind, export_name, module_name, is_strict)) -> ImportNamedTKit.on_ModuleT cx dummy_trace (reason, import_kind, export_name, module_name, is_strict) m | (AnyT (lreason, src), (Annot_CJSRequireT (reason, _) | Annot_ImportModuleNsT (reason, _))) -> Flow_js_utils.check_untyped_import cx ImportValue lreason reason; AnyT.why src reason | (AnyT (lreason, src), Annot_ImportDefaultT (reason, import_kind, _, _)) -> Flow_js_utils.check_untyped_import cx import_kind lreason reason; AnyT.why src reason | (AnyT (lreason, src), Annot_ImportNamedT (reason, import_kind, _, _, _)) -> Flow_js_utils.check_untyped_import cx import_kind lreason reason; AnyT.why src reason (************************************) (* Wildcards (idx, maybe, optional) *) (************************************) | (DefT (_, _, IdxWrapper _), _) | (MaybeT _, _) | (OptionalT _, _) -> (* These are rare in practice. Will consider adding support if we hit this * error case. *) error_unsupported cx t op (*********************) (* Type applications *) (*********************) | (ThisTypeAppT (reason_tapp, c, this, ts), _) -> let reason_op = Type.AConstraint.reason_of_op op in let tc = specialize_class cx c reason_op reason_tapp ts in let t = this_specialize cx reason_tapp this tc in elab_t cx t op | (TypeAppT (reason_tapp, typeapp_use_op, c, ts), _) -> (* NOTE omitting TypeAppExpansion.push_unless_loop check. *) let reason_op = Type.AConstraint.reason_of_op op in let t = mk_typeapp_instance cx ~use_op:typeapp_use_op ~reason_op ~reason_tapp c ts in elab_t cx t op (****************) (* Opaque types *) (****************) | (OpaqueT (r, { underlying_t = Some t; _ }), _) when ALoc.source (aloc_of_reason r) = ALoc.source (def_aloc_of_reason r) -> elab_t cx ~seen t op (********) (* Keys *) (********) | (KeysT _, Annot_ToStringT _) -> t | (KeysT (reason, t), _) -> let t = elab_t cx t (Annot_GetKeysT reason) in elab_t cx t op | (DefT (_, _, ObjT { flags; props_tmap; _ }), Annot_GetKeysT reason_op) -> begin match flags.obj_kind with | UnsealedInFile _ -> with_trust bogus_trust (StrT.why reason_op) | _ -> let dict_t = Obj_type.get_dict_opt flags.obj_kind in (* flow the union of keys of l to keys *) let keylist = Flow_js_utils.keylist_of_props (Context.find_props cx props_tmap) reason_op in let keylist = match dict_t with | None -> keylist | Some { key; _ } -> let key = elab_t cx key (Annot_ToStringT reason_op) in key :: keylist in union_of_ts reason_op keylist end | (DefT (_, _, InstanceT (_, _, _, instance)), Annot_GetKeysT reason_op) -> (* methods are not enumerable, so only walk fields *) let own_props = Context.find_props cx instance.own_props in let keylist = Flow_js_utils.keylist_of_props own_props reason_op in union_of_ts reason_op keylist | (AnyT _, Annot_GetKeysT reason_op) -> with_trust literal_trust (StrT.why reason_op) (***********) (* $Values *) (***********) | (DefT (_, _, ObjT o), Annot_GetValuesT reason) -> Flow_js_utils.get_values_type_of_obj_t cx o reason | (DefT (_, _, InstanceT (_, _, _, { own_props; _ })), Annot_GetValuesT reason) -> Flow_js_utils.get_values_type_of_instance_t cx own_props reason (* Any will always be ok *) | (AnyT (_, src), Annot_GetValuesT reason) -> AnyT.why src reason (********************************) (* Union and intersection types *) (********************************) | (UnionT (reason, rep), Annot_MakeExactT reason_op) -> let ts = UnionRep.members rep in let f t = ExactT (reason_op, t) in let ts' = Base.List.map ts ~f in let reason' = repos_reason (aloc_of_reason reason_op) reason in union_of_ts reason' ts' | (UnionT _, Annot_ObjKitT (reason, use_op, resolve_tool, tool)) -> object_kit_concrete cx use_op op reason resolve_tool tool t | (UnionT (_, rep), _) -> let reason = Type.AConstraint.reason_of_op op in let ts = UnionRep.members rep in let ts = Base.List.map ~f:(fun t -> elab_t cx ~seen t op) ts in union_of_ts reason ts | (IntersectionT _, Annot_ObjKitT (reason, use_op, resolve_tool, tool)) -> object_kit_concrete cx use_op op reason resolve_tool tool t | (IntersectionT _, _) -> (* Handling intersections as inputs would require use of speculation. Instead, * we ask the user to provide a simpler type. *) error_unsupported cx t op (*************) (* Unary not *) (*************) (* any propagation *) | (AnyT _, Annot_NotT _) -> t (* !x when x is of unknown truthiness *) | (DefT (_, trust, BoolT None), Annot_NotT reason) | (DefT (_, trust, StrT AnyLiteral), Annot_NotT reason) | (DefT (_, trust, NumT AnyLiteral), Annot_NotT reason) -> BoolT.at (aloc_of_reason reason) trust (* !x when x is falsy *) | (DefT (_, trust, BoolT (Some false)), Annot_NotT reason) | (DefT (_, trust, SingletonBoolT false), Annot_NotT reason) | (DefT (_, trust, StrT (Literal (_, OrdinaryName ""))), Annot_NotT reason) | (DefT (_, trust, SingletonStrT (OrdinaryName "")), Annot_NotT reason) | (DefT (_, trust, NumT (Literal (_, (0., _)))), Annot_NotT reason) | (DefT (_, trust, SingletonNumT (0., _)), Annot_NotT reason) | (DefT (_, trust, NullT), Annot_NotT reason) | (DefT (_, trust, VoidT), Annot_NotT reason) -> let reason = replace_desc_reason (RBooleanLit true) reason in DefT (reason, trust, BoolT (Some true)) (* !x when x is truthy *) | (_, Annot_NotT reason) -> let reason = replace_desc_reason (RBooleanLit false) reason in DefT (reason, bogus_trust (), BoolT (Some false)) (*****************************) (* Singleton primitive types *) (*****************************) | (DefT (reason, trust, SingletonStrT key), _) -> elab_t cx (DefT (reason, trust, StrT (Literal (None, key)))) op | (DefT (reason, trust, SingletonNumT lit), _) -> elab_t cx (DefT (reason, trust, NumT (Literal (None, lit)))) op | (DefT (reason, trust, SingletonBoolT b), _) -> elab_t cx (DefT (reason, trust, BoolT (Some b))) op | (NullProtoT reason, _) -> elab_t cx (DefT (reason, bogus_trust (), NullT)) op (*********) (* Exact *) (*********) | (ExactT (r, t), _) -> let t = push_type_alias_reason r t in let t = make_exact cx r t in elab_t cx t op | (ShapeT (_, o), Annot_MakeExactT _) -> elab_t cx o op | (DefT (reason_obj, trust, ObjT obj), Annot_MakeExactT reason_op) -> TypeUtil.make_exact_object ~reason_obj trust obj ~reason_op | (AnyT (_, src), Annot_MakeExactT reason_op) -> AnyT.why src reason_op | (DefT (_, trust, VoidT), Annot_MakeExactT reason_op) -> VoidT.why reason_op trust | (DefT (_, trust, EmptyT), Annot_MakeExactT reason_op) -> EmptyT.why reason_op trust | (_, Annot_MakeExactT reason_op) -> Flow_js_utils.add_output cx (Error_message.EUnsupportedExact (reason_op, reason_of_t t)); AnyT.error reason_op (**********) (* Mixins *) (**********) | ( ThisClassT (_, DefT (_, trust, InstanceT (_, _, _, instance)), is_this, this_name), Annot_MixinT r ) -> (* A class can be viewed as a mixin by extracting its immediate properties, * and "erasing" its static and super *) let static = ObjProtoT r in let super = ObjProtoT r in this_class_type (DefT (r, trust, InstanceT (static, super, [], instance))) is_this this_name | ( DefT ( _, _, PolyT { tparams_loc; tparams = xs; t_out = ThisClassT (_, DefT (_, trust, InstanceT (_, _, _, insttype)), is_this, this_name); _; } ), Annot_MixinT r ) -> let static = ObjProtoT r in let super = ObjProtoT r in let instance = DefT (r, trust, InstanceT (static, super, [], insttype)) in poly_type (Type.Poly.generate_id ()) tparams_loc xs (this_class_type instance is_this this_name) | (AnyT (_, src), Annot_MixinT r) -> AnyT.why src r (***********************) (* Type specialization *) (***********************) | ( DefT (_, _, PolyT { tparams_loc; tparams = xs; t_out = t; id }), Annot_SpecializeT (use_op, reason_op, reason_tapp, ts) ) -> let ts = Base.Option.value ts ~default:[] in mk_typeapp_of_poly cx ~use_op ~reason_op ~reason_tapp id tparams_loc xs t ts | ((DefT (_, _, ClassT _) | ThisClassT _), Annot_SpecializeT (_, _, _, None)) -> t | (AnyT _, Annot_SpecializeT _) -> t | (ThisClassT (_, i, _, this_name), Annot_ThisSpecializeT (reason, this)) -> let i = subst cx (Subst_name.Map.singleton this_name this) i in reposition cx (aloc_of_reason reason) i (* this-specialization of non-this-abstracted classes is a no-op *) | (DefT (_, _, ClassT i), Annot_ThisSpecializeT (reason, _this)) -> reposition cx (aloc_of_reason reason) i | (AnyT _, Annot_ThisSpecializeT (reason, _)) -> reposition cx (aloc_of_reason reason) t (**********************) (* Type instantiation *) (**********************) | (DefT (reason_tapp, _, PolyT { tparams_loc; tparams = ids; t_out = t; _ }), _) -> let use_op = unknown_use in let reason_op = Type.AConstraint.reason_of_op op in let t = instantiate_poly cx ~use_op ~reason_op ~reason_tapp (tparams_loc, ids, t) in elab_t cx t op | (ThisClassT (r, i, is_this, this_name), _) -> let reason = Type.AConstraint.reason_of_op op in let t = fix_this_class cx reason (r, i, is_this, this_name) in elab_t cx t op (*****************************) (* React Abstract Components *) (*****************************) | (DefT (r, _, ReactAbstractComponentT _), (Annot_GetPropT _ | Annot_GetElemT _)) -> let statics = Flow_js_utils.lookup_builtin_strict cx (OrdinaryName "React$AbstractComponentStatics") r in elab_t cx statics op (****************) (* Custom types *) (****************) | (DefT (reason, trust, CharSetT _), _) -> elab_t cx (StrT.why reason trust) op | ( CustomFunT (_, ReactPropType (React.PropType.Primitive (false, t))), Annot_GetPropT (reason_op, _, Named (_, OrdinaryName "isRequired")) ) -> let prop_type = React.PropType.Primitive (true, t) in CustomFunT (reason_op, ReactPropType prop_type) | (CustomFunT (reason, ReactPropType (React.PropType.Primitive (req, _))), _) when function_like_op op -> let builtin_name = if req then "ReactPropsCheckType" else "ReactPropsChainableTypeChecker" in let l = get_builtin_type cx reason (OrdinaryName builtin_name) in elab_t cx l op | (CustomFunT (reason, ReactPropType (React.PropType.Complex kind)), _) when function_like_op op -> let l = get_builtin_prop_type cx reason kind in elab_t cx l op | (CustomFunT (r, _), _) when function_like_op op -> elab_t cx (FunProtoT r) op (**************) (* Shape type *) (**************) | (ShapeT (r, o), _) -> elab_t cx ~seen (reposition cx (aloc_of_reason r) o) op (*****************) (* ObjTestProtoT *) (*****************) | (AnyT (_, src), Annot_ObjTestProtoT reason_op) -> AnyT.why src reason_op | (DefT (_, trust, NullT), Annot_ObjTestProtoT reason_op) -> NullProtoT.why reason_op trust | (_, Annot_ObjTestProtoT reason_op) -> if Flow_js_utils.object_like t then reposition cx (aloc_of_reason reason_op) t else let () = Flow_js_utils.add_output cx (Error_message.EInvalidPrototype (aloc_of_reason reason_op, reason_of_t t)) in ObjProtoT.why reason_op |> with_trust bogus_trust (***************) (* Get statics *) (***************) | (DefT (_, _, InstanceT (static, _, _, _)), Annot_GetStaticsT reason_op) -> reposition cx (aloc_of_reason reason_op) static | (AnyT (_, src), Annot_GetStaticsT reason_op) -> AnyT.why src reason_op | (ObjProtoT _, Annot_GetStaticsT reason_op) -> (* ObjProtoT not only serves as the instance type of the root class, but * also as the statics of the root class. *) reposition cx (aloc_of_reason reason_op) t (***************) (* LookupT pt1 *) (***************) | ( DefT (_lreason, _, InstanceT (_, super, _, instance)), Annot_LookupT (reason_op, use_op, (Named (_, x) as propref)) ) -> let own_props = Context.find_props cx instance.own_props in let proto_props = Context.find_props cx instance.proto_props in let pmap = NameUtils.Map.union own_props proto_props in (match NameUtils.Map.find_opt x pmap with | None -> Get_prop_helper.cg_lookup_ cx use_op super reason_op propref | Some p -> GetPropTKit.perform_read_prop_action cx dummy_trace use_op propref p reason_op) | (DefT (_, _, InstanceT _), Annot_LookupT (reason_op, _, Computed _)) -> let loc = aloc_of_reason reason_op in Flow_js_utils.add_output cx Error_message.(EInternal (loc, InstanceLookupComputed)); AnyT.error reason_op | (DefT (_, _, ObjT o), Annot_LookupT (reason_op, use_op, propref)) -> (match GetPropTKit.get_obj_prop cx dummy_trace o propref reason_op with | Some (p, _) -> GetPropTKit.perform_read_prop_action cx dummy_trace use_op propref p reason_op | None -> Get_prop_helper.cg_lookup_ cx use_op o.proto_t reason_op propref) | (AnyT _, Annot_LookupT (reason_op, use_op, propref)) -> let p = Field (None, AnyT.untyped reason_op, Polarity.Neutral) in GetPropTKit.perform_read_prop_action cx dummy_trace use_op propref p reason_op (************) (* ObjRestT *) (************) | (DefT (_, _, ObjT { props_tmap; flags; _ }), Annot_ObjRestT (reason, xs)) -> Flow_js_utils.objt_to_obj_rest cx props_tmap flags reason xs | (DefT (_, _, InstanceT _), Annot_ObjRestT _) -> (* This implementation relies on unsealed objects and set-prop logic that is * hard to implement in annotation inference. *) error_unsupported cx t op | (AnyT (_, src), Annot_ObjRestT (reason, _)) -> AnyT.why src reason | (ObjProtoT _, Annot_ObjRestT (reason, _)) -> Obj_type.mk_unsealed cx reason ~proto:t | (DefT (_, _, (NullT | VoidT)), Annot_ObjRestT (reason, _)) -> (* mirroring Object.assign semantics, treat null/void as empty objects *) Obj_type.mk_unsealed cx reason (************) (* GetPropT *) (************) | (DefT (r, _, InstanceT (_, super, _, insttype)), Annot_GetPropT (reason_op, use_op, propref)) -> GetPropTKit.on_InstanceT cx dummy_trace ~l:t r super insttype use_op reason_op propref | (DefT (_, _, ObjT _), Annot_GetPropT (reason_op, _, Named (_, OrdinaryName "constructor"))) -> Unsoundness.why Constructor reason_op | (DefT (reason_obj, _, ObjT o), Annot_GetPropT (reason_op, use_op, propref)) -> GetPropTKit.read_obj_prop cx dummy_trace ~use_op o propref reason_obj reason_op None | (AnyT _, Annot_GetPropT (reason_op, _, _)) -> AnyT (reason_op, Untyped) | (DefT (reason, _, ClassT instance), Annot_GetPropT (_, _, Named (_, OrdinaryName "prototype"))) -> reposition cx (aloc_of_reason reason) instance (**************) (* Object Kit *) (**************) | (_, Annot_ObjKitT (reason, use_op, resolve_tool, tool)) -> object_kit_concrete cx use_op op reason resolve_tool tool t (********************) (* GetElemT / ElemT *) (********************) | (DefT (_, trust, StrT _), Annot_GetElemT (reason_op, _use_op, _index)) -> (* NOTE bypassing check that index is a number *) StrT.why reason_op trust | ((DefT (_, _, (ObjT _ | ArrT _)) | AnyT _), Annot_GetElemT (reason_op, use_op, key)) -> elab_t cx key (Annot_ElemT (reason_op, use_op, t)) | (DefT (_, _, InstanceT _), Annot_GetElemT (reason, use_op, _i)) -> (* NOTE bypassing key check *) elab_t cx t (Annot_GetPropT (reason, use_op, Named (reason, OrdinaryName "$value"))) | (_, Annot_ElemT (reason_op, use_op, (DefT (_, _, ObjT _) as obj))) -> let propref = Flow_js_utils.propref_for_elem_t t in elab_t cx obj (Annot_GetPropT (reason_op, use_op, propref)) | (_, Annot_ElemT (reason_op, _use_op, (AnyT _ as _obj))) -> let value = AnyT.untyped reason_op in reposition cx (aloc_of_reason reason_op) value | (AnyT _, Annot_ElemT (reason_op, _, DefT (_, _, ArrT arrtype))) -> let value = elemt_of_arrtype arrtype in reposition cx (aloc_of_reason reason_op) value | (l, Annot_ElemT (reason_op, use_op, DefT (reason_tup, _, ArrT arrtype))) when Flow_js_utils.numeric l -> let (value, _) = Flow_js_utils.array_elem_check ~write_action:false cx dummy_trace l use_op reason_op reason_tup arrtype in reposition cx (aloc_of_reason reason_op) value | (DefT (_, trust, ObjT o), Annot_ObjKeyMirror reason_op) -> Flow_js_utils.obj_key_mirror cx trust o reason_op | (DefT (_, trust, ObjT o), Annot_ObjMapConst (reason_op, target)) -> Flow_js_utils.obj_map_const cx trust o reason_op target (***********************) (* Opaque types (pt 2) *) (***********************) | (OpaqueT (_, { super_t = Some t; _ }), _) -> elab_t cx t op (************************) (* Unary minus operator *) (************************) | (DefT (_, trust, NumT lit), Annot_UnaryMinusT reason_op) -> let num = match lit with | Literal (_, (value, raw)) -> let (value, raw) = Flow_ast_utils.negate_number_literal (value, raw) in DefT (replace_desc_reason RNumber reason_op, trust, NumT (Literal (None, (value, raw)))) | AnyLiteral | Truthy -> t in num | (AnyT _, Annot_UnaryMinusT reason_op) -> AnyT.untyped reason_op (********************) (* Function Statics *) (********************) | (DefT (reason, _, FunT (static, _)), _) when object_like_op op -> let static = reposition cx (aloc_of_reason reason) static in elab_t cx static op (*****************) (* Class statics *) (*****************) | (DefT (reason, _, ClassT instance), _) when object_like_op op -> let t = get_statics cx reason instance in elab_t cx t op (*********) (* Enums *) (*********) | ( DefT (enum_reason, trust, EnumObjectT enum), Annot_GetPropT (access_reason, use_op, Named (prop_reason, member_name)) ) -> let access = (use_op, access_reason, None, (prop_reason, member_name)) in GetPropTKit.on_EnumObjectT cx dummy_trace enum_reason trust enum access | (DefT (enum_reason, _, EnumObjectT _), Annot_GetElemT (reason_op, _, elem)) -> let reason = reason_of_t elem in Flow_js_utils.add_output cx (Error_message.EEnumInvalidMemberAccess { member_name = None; suggestion = None; reason; enum_reason } ); AnyT.error reason_op (***************) (* LookupT pt2 *) (***************) | (ObjProtoT _, Annot_LookupT (reason_op, _, Named (_, x))) when Flow_js_utils.is_object_prototype_method x -> Flow_js_utils.lookup_builtin_strict cx (OrdinaryName "Object") reason_op | (FunProtoT _, Annot_LookupT (reason_op, _, Named (_, x))) when Flow_js_utils.is_function_prototype x -> Flow_js_utils.lookup_builtin_strict cx (OrdinaryName "Function") reason_op | ( (DefT (reason, _, NullT) | ObjProtoT reason | FunProtoT reason), Annot_LookupT (reason_op, use_op, (Named (reason_prop, x) as propref)) ) -> let error_message = if Reason.is_builtin_reason ALoc.source reason then Error_message.EBuiltinLookupFailed { reason = reason_prop; name = Some x; potential_generator = None } else let suggestion = None in Error_message.EStrictLookupFailed { reason_prop; reason_obj = reason_op; name = Some x; use_op = Some use_op; suggestion } in Flow_js_utils.add_output cx error_message; let p = Field (None, AnyT.error_of_kind UnresolvedName reason_op, Polarity.Neutral) in GetPropTKit.perform_read_prop_action cx dummy_trace use_op propref p reason_op (****************************************) (* Object, function, etc. library calls *) (****************************************) | (ObjProtoT reason, _) -> let use_desc = true in let obj_proto = get_builtin_type cx reason ~use_desc (OrdinaryName "Object") in elab_t cx obj_proto op | (FunProtoT reason, _) -> let use_desc = true in let fun_proto = get_builtin_type cx reason ~use_desc (OrdinaryName "Function") in elab_t cx fun_proto op (*************) (* ToStringT *) (*************) | (DefT (_, _, StrT _), Annot_ToStringT _) -> t | (_, Annot_ToStringT reason_op) -> with_trust bogus_trust (StrT.why reason_op) (************) (* GetPropT *) (************) | (DefT (reason, _, ArrT (ArrayAT (t, _))), (Annot_GetPropT _ | Annot_LookupT _)) -> let arr = get_builtin_typeapp cx reason (OrdinaryName "Array") [t] in elab_t cx arr op | ( DefT (reason, trust, ArrT (TupleAT (_, ts))), Annot_GetPropT (reason_op, _, Named (_, OrdinaryName "length")) ) -> GetPropTKit.on_array_length cx dummy_trace reason trust ts reason_op | ( DefT (reason, _, ArrT ((TupleAT _ | ROArrayAT _) as arrtype)), (Annot_GetPropT _ | Annot_LookupT _) ) -> let t = elemt_of_arrtype arrtype in elab_t cx (get_builtin_typeapp cx reason (OrdinaryName "$ReadOnlyArray") [t]) op (************************) (* Promoting primitives *) (************************) | (DefT (reason, _, StrT _), _) when primitive_promoting_op op -> let builtin = get_builtin_type cx reason ~use_desc:true (OrdinaryName "String") in elab_t cx builtin op | (DefT (reason, _, NumT _), _) when primitive_promoting_op op -> let builtin = get_builtin_type cx reason ~use_desc:true (OrdinaryName "Number") in elab_t cx builtin op | (DefT (reason, _, BoolT _), _) when primitive_promoting_op op -> let builtin = get_builtin_type cx reason ~use_desc:true (OrdinaryName "Boolean") in elab_t cx builtin op | (DefT (reason, _, SymbolT), _) when primitive_promoting_op op -> let builtin = get_builtin_type cx reason ~use_desc:true (OrdinaryName "Symbol") in elab_t cx builtin op | (DefT (lreason, _, MixedT Mixed_function), (Annot_GetPropT _ | Annot_LookupT _)) -> elab_t cx (FunProtoT lreason) op | (_, _) -> let open Error_message in let reason_op = reason_of_op op in let lower = (reason_of_t t, Flow_js_utils.error_message_kind_of_lower t) in let upper = (reason_op, IncompatibleUnclassified (string_of_operation op)) in let use_op = use_op_of_operation op in Flow_js_utils.add_output cx (EIncompatible { lower; upper; use_op; branches = [] }); AnyT.error reason_op and get_builtin_type cx reason ?(use_desc = false) x = let t = Flow_js_utils.lookup_builtin_strict cx x reason in mk_instance cx reason ~use_desc ~reason_type:(reason_of_t t) t and get_builtin_prop_type cx reason tool = let x = React.PropType.( match tool with | ArrayOf -> "React$PropTypes$arrayOf" | InstanceOf -> "React$PropTypes$instanceOf" | ObjectOf -> "React$PropTypes$objectOf" | OneOf -> "React$PropTypes$oneOf" | OneOfType -> "React$PropTypes$oneOfType" | Shape -> "React$PropTypes$shape" ) in get_builtin_type cx reason (OrdinaryName x) and specialize cx t use_op reason_op reason_tapp ts = elab_t cx t (Annot_SpecializeT (use_op, reason_op, reason_tapp, ts)) and this_specialize cx reason this t = elab_t cx t (Annot_ThisSpecializeT (reason, this)) and specialize_class cx c reason_op reason_tapp ts = match ts with | None -> c | Some ts -> specialize cx c unknown_use reason_op reason_tapp (Some ts) and mk_type_reference cx reason c = let f id = resolve_id cx id (elab_t cx c (Annot_UseT_TypeT reason)) in let tvar = mk_lazy_tvar cx reason f in AnnotT (reason, tvar, false) and mk_instance cx instance_reason ?(use_desc = false) ~reason_type c = let source = elab_t cx c (Annot_UseT_TypeT reason_type) in AnnotT (instance_reason, source, use_desc) and mk_typeapp_instance cx ~use_op ~reason_op ~reason_tapp c ts = let t = specialize cx c use_op reason_op reason_tapp (Some ts) in mk_instance cx reason_tapp ~reason_type:(reason_of_t c) t and get_statics cx reason t = elab_t cx t (Annot_GetStaticsT reason) and get_prop cx use_op reason name t = elab_t cx t (Annot_GetPropT (reason, use_op, Named (reason, name))) and get_elem cx use_op reason ~key t = elab_t cx t (Annot_GetElemT (reason, use_op, key)) and qualify_type cx use_op reason (reason_name, name) t = let open Type in let f id = let t = elab_t cx t (Annot_GetPropT (reason, use_op, Named (reason_name, name))) in resolve_id cx id t in mk_lazy_tvar cx reason f (* Unlike Flow_js, types in this module are 0->1, so there is no need for a * mechanism similar to BecomeT of Flow_js. *) and mk_typeof_annotation cx ?trace:_ reason t = let annot_loc = aloc_of_reason reason in let t = reposition cx (aloc_of_reason reason) t in AnnotT (opt_annot_reason ~annot_loc reason, t, false) and assert_export_is_type cx reason name t = let f id = let t = elab_t cx t (Annot_AssertExportIsTypeT (reason, Reason.OrdinaryName name)) in resolve_id cx id t in mk_lazy_tvar cx reason f and cjs_require cx t reason is_strict = elab_t cx t (Annot_CJSRequireT (reason, is_strict)) and export_named cx reason kind named t = elab_t cx t (Annot_ExportNamedT (reason, named, kind)) and cjs_extract_named_exports cx reason local_module t = elab_t cx t (Annot_CJSExtractNamedExportsT (reason, local_module)) and import_typeof cx reason export_name t = elab_t cx t (Annot_ImportTypeofT (reason, export_name)) and import_default cx reason import_kind export_name module_name is_strict t = elab_t cx t (Annot_ImportDefaultT (reason, import_kind, (export_name, module_name), is_strict)) and import_named cx reason import_kind export_name module_name is_strict t = elab_t cx t (Annot_ImportNamedT (reason, import_kind, export_name, module_name, is_strict)) and import_ns cx reason is_strict t = elab_t cx t (Annot_ImportModuleNsT (reason, is_strict)) and copy_named_exports cx ~from_ns reason ~module_t = elab_t cx from_ns (Annot_CopyNamedExportsT (reason, module_t)) and copy_type_exports cx ~from_ns reason ~module_t = elab_t cx from_ns (Annot_CopyTypeExportsT (reason, module_t)) and unary_minus cx reason_op t = elab_t cx t (Annot_UnaryMinusT reason_op) and unary_not cx reason_op t = elab_t cx t (Annot_NotT reason_op) and mixin cx reason t = elab_t cx t (Annot_MixinT reason) and obj_rest cx reason xs t = elab_t cx t (Annot_ObjRestT (reason, xs)) and arr_rest cx _use_op reason_op _i t = error_unsupported_reason cx t reason_op and object_kit_concrete = let rec widen_obj_type cx ~use_op reason t = match t with | OpenT (_, id) -> let open Constraint in begin match Context.find_graph cx id with | exception Union_find.Tvar_not_found _ -> error_internal_reason cx "widen_obj_type" reason | Unresolved _ | Resolved _ -> failwith "widen_obj_type unexpected non-FullyResolved tvar" | FullyResolved (_, (lazy t)) -> widen_obj_type cx ~use_op reason t end | UnionT (r, rep) -> UnionT ( r, UnionRep.ident_map (fun t -> if is_proper_def t then widen_obj_type cx ~use_op reason t else t) rep ) | t -> t in let add_output cx msg : unit = Flow_js_utils.add_output cx msg in let return _cx _use_op t = t in let recurse cx use_op reason resolve_tool tool x = object_kit cx use_op reason resolve_tool tool x in let object_spread options state cx = let dict_check _cx _use_op _d1 _d2 = () in Slice_utils.object_spread ~dict_check ~widen_obj_type ~add_output ~return ~recurse options state cx in let object_rest options state cx = let return _ _ _ t = t in (* No subtyping checks in annotation inference *) let subt_check ~use_op:_ _ _ = () in Slice_utils.object_rest ~add_output ~return ~recurse ~subt_check options state cx in let object_read_only cx _use_op = Slice_utils.object_read_only cx in let object_partial cx _use_op = Slice_utils.object_partial cx in let next op cx use_op tool reason x = Object.( match tool with | Spread (options, state) -> object_spread options state cx use_op reason x | Rest (options, state) -> object_rest options state cx use_op reason x | Partial -> object_partial cx use_op reason x | ReadOnly -> object_read_only cx use_op reason x | ReactConfig _ -> error_internal cx "ReactConfig" op | ObjectRep -> error_internal cx "ObjectRep" op | ObjectWiden _ -> error_internal cx "ObjectWiden" op ) in let statics = get_statics in fun cx use_op op reason resolve_tool tool t -> Slice_utils.run ~add_output ~return ~next:(next op) ~recurse ~statics cx use_op reason resolve_tool tool t and object_kit cx use_op reason resolve_tool tool t = elab_t cx t (Annot_ObjKitT (reason, use_op, resolve_tool, tool)) and object_spread cx use_op reason target state t = let resolve_tool = Type.Object.(Resolve Next) in let tool = Type.Object.Spread (target, state) in object_kit cx use_op reason resolve_tool tool t and object_rest cx use_op reason target state t = let resolve_tool = Type.Object.(Resolve Next) in let tool = Type.Object.Rest (target, state) in object_kit cx use_op reason resolve_tool tool t and make_readonly cx use_op reason t = let resolve_tool = Type.Object.(Resolve Next) in object_kit cx use_op reason resolve_tool Type.Object.ReadOnly t and make_exact cx reason t = elab_t cx t (Annot_MakeExactT reason) and obj_test_proto cx reason_op t = elab_t cx t (Annot_ObjTestProtoT reason_op) end