From a1f78dd3c823d1b26a0917976c2cc7a6f824dfe0 Mon Sep 17 00:00:00 2001 From: Panos Vekris Date: Wed, 5 Mar 2025 17:10:11 -0800 Subject: [PATCH] [flow] Singleton types get a with "generalizable" field Summary: In the following code under natural inference ``` const x1 = "a"; const o1 = {f: x1}; ``` we would like to infer ``` x1: "a" // SingletonStrT("a") o1: {f:string} // ObjT {f: StrGeneralT} ``` At the same time, an annotated version of this code: ``` const x2: "a" = "a"; const o2 = {f: x2}; ``` should yield ``` x2: "a" // SingletonStrT("a") o2: {f:"a"} // ObjT {f: SingletonStrT("a")} ``` Note the difference between `o1` and `o2`. To enable this behavior we need to be able to distinguish between the two types of `SingletonStrT` that we infer for `x1` and `x2`. The key difference is whether we should allow a `SingletonStrT` to "generalize" to `StrGeneralT`. Roughly, a string literal type is generalizable iff it does not originate from an annotation, or a value under `as const`, or `Object.freeze()`. This diff adds a field `from_annot` to `SingletonStrT`, `SingletonNumT`, etc, and populates it accordingly. This field has no impact yet in typechecking behavior. It will only be used later to inform the generalization process. Changelog: [internal] Reviewed By: SamChou19815 Differential Revision: D66659579 fbshipit-source-id: 148f2e35de53debc600d17f735dc51cbd771d190 --- src/typing/annotation_inference.ml | 13 ++++---- src/typing/debug_js.ml | 10 +++--- src/typing/env_resolution.ml | 5 ++- src/typing/flow_js.ml | 21 +++++++----- src/typing/flow_js_utils.ml | 44 +++++++++++++++---------- src/typing/object_kit.ml | 2 +- src/typing/predicate_kit.ml | 46 +++++++++++++------------- src/typing/react_kit.ml | 10 +++--- src/typing/renders_kit.ml | 8 +++-- src/typing/slice_utils.ml | 7 +++- src/typing/statement.ml | 14 ++++---- src/typing/subtyping_kit.ml | 50 ++++++++++++++++++---------- src/typing/ty_normalizer.ml | 14 ++++---- src/typing/type.ml | 30 ++++++++++++----- src/typing/typeUtil.ml | 25 ++++++++------ src/typing/type_annotation.ml | 14 ++++---- src/typing/type_filter.ml | 53 ++++++++++++++++-------------- src/typing/type_hint.ml | 14 +++++--- src/typing/type_operation_utils.ml | 6 ++-- src/typing/type_sig_merge.ml | 16 ++++----- 20 files changed, 235 insertions(+), 167 deletions(-) diff --git a/src/typing/annotation_inference.ml b/src/typing/annotation_inference.ml index dbc371879b3..228f0b8c611 100644 --- a/src/typing/annotation_inference.ml +++ b/src/typing/annotation_inference.ml @@ -771,11 +771,11 @@ module rec ConsGen : S = struct BoolModuleT.at (loc_of_reason reason) (* !x when x is falsy *) | (DefT (_, BoolT_UNSOUND false), Annot_NotT reason) - | (DefT (_, SingletonBoolT false), Annot_NotT reason) + | (DefT (_, SingletonBoolT { value = false; _ }), Annot_NotT reason) | (DefT (_, StrT_UNSOUND (_, OrdinaryName "")), Annot_NotT reason) - | (DefT (_, SingletonStrT (OrdinaryName "")), Annot_NotT reason) + | (DefT (_, SingletonStrT { value = OrdinaryName ""; _ }), Annot_NotT reason) | (DefT (_, NumT_UNSOUND (_, (0., _))), Annot_NotT reason) - | (DefT (_, SingletonNumT (0., _)), Annot_NotT reason) + | (DefT (_, SingletonNumT { value = (0., _); _ }), Annot_NotT reason) | (DefT (_, NullT), Annot_NotT reason) | (DefT (_, VoidT), Annot_NotT reason) -> let reason = replace_desc_reason (RBooleanLit true) reason in @@ -1152,11 +1152,12 @@ module rec ConsGen : S = struct (*****************************) | (DefT (reason, NumericStrKeyT (_, s)), _) -> elab_t cx (DefT (reason, StrT_UNSOUND (None, OrdinaryName s))) op - | (DefT (reason, SingletonStrT key), _) -> + | (DefT (reason, SingletonStrT { value = key; _ }), _) -> elab_t cx (DefT (reason, StrT_UNSOUND (None, key))) op - | (DefT (reason, SingletonNumT lit), _) -> + | (DefT (reason, SingletonNumT { value = lit; _ }), _) -> elab_t cx (DefT (reason, NumT_UNSOUND (None, lit))) op - | (DefT (reason, SingletonBoolT b), _) -> elab_t cx (DefT (reason, BoolT_UNSOUND b)) op + | (DefT (reason, SingletonBoolT { value = b; _ }), _) -> + elab_t cx (DefT (reason, BoolT_UNSOUND b)) op | (NullProtoT reason, _) -> elab_t cx (DefT (reason, NullT)) op (********************) (* Function Statics *) diff --git a/src/typing/debug_js.ml b/src/typing/debug_js.ml index d5b497ed33f..0635a520019 100644 --- a/src/typing/debug_js.ml +++ b/src/typing/debug_js.ml @@ -345,10 +345,12 @@ let rec dump_t_ (depth, tvars) cx t = ) t | DefT (_, NumericStrKeyT (_, s)) -> p ~extra:s t - | DefT (_, SingletonStrT s) -> p ~extra:(spf "%S" (display_string_of_name s)) t - | DefT (_, SingletonNumT (_, s)) -> p ~extra:s t - | DefT (_, SingletonBoolT b) -> p ~extra:(spf "%B" b) t - | DefT (_, SingletonBigIntT (_, s)) -> p ~extra:s t + | DefT (_, SingletonStrT { from_annot; value = s }) -> + p ~extra:(spf "%S (from_annot=%b)" (display_string_of_name s) from_annot) t + | DefT (_, SingletonNumT { from_annot; value = (_, s) }) -> + p ~extra:(s ^ spf " (from_annot=%b)" from_annot) t + | DefT (_, SingletonBoolT { value = b; _ }) -> p ~extra:(spf "%B" b) t + | DefT (_, SingletonBigIntT { value = (_, s); _ }) -> p ~extra:s t | NamespaceT { namespace_symbol; values_type; types_tmap } -> p t diff --git a/src/typing/env_resolution.ml b/src/typing/env_resolution.ml index a7f4f2cc425..281034cb0a2 100644 --- a/src/typing/env_resolution.ml +++ b/src/typing/env_resolution.ml @@ -206,7 +206,10 @@ let resolve_hint cx loc hint = UnionT (mk_reason (RCustom "providers") loc, UnionRep.make t1 t2 ts) | WriteLocHint (kind, loc) -> Type_env.checked_find_loc_env_write cx kind loc | StringLiteralType name -> - DefT (mk_reason (RIdentifier (OrdinaryName name)) loc, SingletonStrT (OrdinaryName name)) + DefT + ( mk_reason (RIdentifier (OrdinaryName name)) loc, + SingletonStrT { from_annot = true; value = OrdinaryName name } + ) | ReactFragmentType -> Flow_js_utils.ImportExportUtils.get_implicitly_imported_react_type cx diff --git a/src/typing/flow_js.ml b/src/typing/flow_js.ml index 845a0c7fb34..b1b34c7c0db 100644 --- a/src/typing/flow_js.ml +++ b/src/typing/flow_js.ml @@ -1433,8 +1433,8 @@ struct ) -> (match (drop_generic key, flags.obj_kind) with (* If we have a literal string and that property exists *) - | (DefT (_, (StrT_UNSOUND (_, x) | SingletonStrT x)), _) when Context.has_prop cx mapr x - -> + | (DefT (_, (StrT_UNSOUND (_, x) | SingletonStrT { value = x; _ })), _) + when Context.has_prop cx mapr x -> () (* If we have a dictionary, try that next *) | (_, Indexed { key = expected_key; _ }) -> @@ -1442,7 +1442,7 @@ struct | _ -> let (prop, suggestion) = match drop_generic key with - | DefT (_, (StrT_UNSOUND (_, prop) | SingletonStrT prop)) -> + | DefT (_, (StrT_UNSOUND (_, prop) | SingletonStrT { value = prop; _ })) -> (Some prop, prop_typo_suggestion cx [mapr] (display_string_of_name prop)) | _ -> (None, None) in @@ -1461,9 +1461,12 @@ struct HasOwnPropT ( use_op, reason_op, - ( ( DefT (_, (StrT_UNSOUND (_, x) | SingletonStrT x)) - | GenericT { bound = DefT (_, (StrT_UNSOUND (_, x) | SingletonStrT x)); _ } ) as - key + ( ( DefT (_, (StrT_UNSOUND (_, x) | SingletonStrT { value = x; _ })) + | GenericT + { + bound = DefT (_, (StrT_UNSOUND (_, x) | SingletonStrT { value = x; _ })); + _; + } ) as key ) ) ) -> @@ -3965,7 +3968,9 @@ struct let r = reason_of_t value_t in match index with | None -> NumModuleT.why r - | Some i -> DefT (r, SingletonNumT (float_of_int i, string_of_int i)) + | Some i -> + DefT + (r, SingletonNumT { from_annot = true; value = (float_of_int i, string_of_int i) }) in Slice_utils.mk_mapped_prop_type ~use_op @@ -5268,7 +5273,7 @@ struct suggestion = None; } ) - | ( DefT (reason, (NumT_UNSOUND (_, (value, _)) | SingletonNumT (value, _))), + | ( DefT (reason, (NumT_UNSOUND (_, (value, _)) | SingletonNumT { value = (value, _); _ })), WriteComputedObjPropCheckT { reason_key; _ } ) -> let kind = Flow_intermediate_error_types.InvalidObjKey.kind_of_num_value value in diff --git a/src/typing/flow_js_utils.ml b/src/typing/flow_js_utils.ml index d363d7b6733..2df13c87897 100644 --- a/src/typing/flow_js_utils.ml +++ b/src/typing/flow_js_utils.ml @@ -306,7 +306,7 @@ let ground_subtype = function ) when String.starts_with ~prefix:prefix2 prefix1 -> true - | ( DefT (_, (StrT_UNSOUND (None, OrdinaryName s) | SingletonStrT (OrdinaryName s))), + | ( DefT (_, (StrT_UNSOUND (None, OrdinaryName s) | SingletonStrT { value = OrdinaryName s; _ })), UseT (_, StrUtilT { reason = _; op = StrPrefix prefix; remainder = None }) ) when String.starts_with ~prefix s -> @@ -316,7 +316,7 @@ let ground_subtype = function ) when String.ends_with ~suffix:suffix2 suffix1 -> true - | ( DefT (_, (StrT_UNSOUND (None, OrdinaryName s) | SingletonStrT (OrdinaryName s))), + | ( DefT (_, (StrT_UNSOUND (None, OrdinaryName s) | SingletonStrT { value = OrdinaryName s; _ })), UseT (_, StrUtilT { reason = _; op = StrSuffix suffix; remainder = None }) ) when String.ends_with ~suffix s -> @@ -1015,7 +1015,7 @@ let obj_key_mirror cx o reason_op = in let map_field key t = let reason = replace_desc_reason (RStringLit key) reason_op in - map_t (DefT (reason, SingletonStrT key)) t + map_t (DefT (reason, SingletonStrT { from_annot = true; value = key })) t in let props_tmap = Context.find_props cx o.props_tmap @@ -2699,8 +2699,12 @@ module GetPropT_kit (F : Get_prop_helper_sig) = struct add_output cx Error_message.(EInternal (loc, PropRefComputedLiteral)); F.error_type cx trace reason_op | GenericT - { bound = DefT (_, (NumT_UNSOUND (_, (value, _)) | SingletonNumT (value, _))); _ } - | DefT (_, (NumT_UNSOUND (_, (value, _)) | SingletonNumT (value, _))) -> + { + bound = + DefT (_, (NumT_UNSOUND (_, (value, _)) | SingletonNumT { value = (value, _); _ })); + _; + } + | DefT (_, (NumT_UNSOUND (_, (value, _)) | SingletonNumT { value = (value, _); _ })) -> let reason_prop = reason_of_t elem_t in let kind = Flow_intermediate_error_types.InvalidObjKey.kind_of_num_value value in add_output cx (Error_message.EObjectComputedPropertyAccess (reason_op, reason_prop, kind)); @@ -2749,8 +2753,10 @@ let array_elem_check in let (can_write_tuple, value, use_op) = match l with - | DefT (index_reason, (NumT_UNSOUND (_, (float_value, _)) | SingletonNumT (float_value, _))) -> - begin + | DefT + ( index_reason, + (NumT_UNSOUND (_, (float_value, _)) | SingletonNumT { value = (float_value, _); _ }) + ) -> begin match elements with | None -> (false, elem_t, use_op) | Some elements -> @@ -2843,19 +2849,21 @@ let array_elem_check (value, is_tuple, use_op, react_dro) let propref_for_elem_t = function - | OpaqueT (reason, { super_t = Some (DefT (_, SingletonStrT name)); _ }) - | GenericT { bound = DefT (_, (SingletonStrT name | StrT_UNSOUND (_, name))); reason; _ } - | DefT (reason, (SingletonStrT name | StrT_UNSOUND (_, name))) -> + | OpaqueT (reason, { super_t = Some (DefT (_, SingletonStrT { value = name; _ })); _ }) + | GenericT + { bound = DefT (_, (SingletonStrT { value = name; _ } | StrT_UNSOUND (_, name))); reason; _ } + | DefT (reason, (SingletonStrT { value = name; _ } | StrT_UNSOUND (_, name))) -> let reason = replace_desc_reason (RProperty (Some name)) reason in mk_named_prop ~reason ~from_indexed_access:true name - | OpaqueT (reason_num, { super_t = Some (DefT (_, SingletonNumT (value, raw))); _ }) + | OpaqueT (reason_num, { super_t = Some (DefT (_, SingletonNumT { value = (value, raw); _ })); _ }) | GenericT { - bound = DefT (_, (NumT_UNSOUND (_, (value, raw)) | SingletonNumT (value, raw))); + bound = + DefT (_, (NumT_UNSOUND (_, (value, raw)) | SingletonNumT { value = (value, raw); _ })); reason = reason_num; _; } - | DefT (reason_num, (NumT_UNSOUND (_, (value, raw)) | SingletonNumT (value, raw))) + | DefT (reason_num, (NumT_UNSOUND (_, (value, raw)) | SingletonNumT { value = (value, raw); _ })) when Js_number.is_float_safe_integer value -> let reason = replace_desc_reason (RProperty (Some (OrdinaryName raw))) reason_num in let name = OrdinaryName (Dtoa.ecma_string_of_float value) in @@ -2868,7 +2876,7 @@ let keylist_of_props props reason_op = match name with | OrdinaryName _ -> let reason = replace_desc_new_reason (RStringLit name) reason_op in - DefT (reason, SingletonStrT name) :: acc + DefT (reason, SingletonStrT { from_annot = true; value = name }) :: acc | InternalName _ -> acc) props [] @@ -2984,9 +2992,9 @@ let flow_unary_arith cx l reason kind = | (Minus, DefT (lreason, NumT_UNSOUND (_, lit))) -> let (reason, lit) = unary_negate_lit ~annot_loc:(loc_of_reason reason) lreason lit in DefT (reason, NumT_UNSOUND (None, lit)) - | (Minus, DefT (lreason, SingletonNumT lit)) -> + | (Minus, DefT (lreason, SingletonNumT { from_annot; value = lit })) -> let (reason, lit) = unary_negate_lit ~annot_loc:(loc_of_reason reason) lreason lit in - DefT (reason, SingletonNumT lit) + DefT (reason, SingletonNumT { from_annot; value = lit }) | (Minus, DefT (_, NumGeneralT _)) -> l | (Minus, DefT (_, BigIntT_UNSOUND (_, (value, raw)))) -> let (value, raw) = Flow_ast_utils.negate_bigint_literal (value, raw) in @@ -3330,7 +3338,7 @@ end = struct let on_concretized_bad_non_element_normalization normalization_cx = function | DefT (invalid_type_reason, BoolT_UNSOUND false) - | DefT (invalid_type_reason, SingletonBoolT false) + | DefT (invalid_type_reason, SingletonBoolT { value = false; _ }) | DefT (invalid_type_reason, NullT) | DefT (invalid_type_reason, VoidT) -> TypeCollector.add normalization_cx.type_collector (AnyT.error normalization_cx.result_reason); @@ -3373,7 +3381,7 @@ end = struct invalid_type_reasons = Nel.one generic_reason; } ) - | DefT (reason, SingletonStrT (OrdinaryName "svg")) -> + | DefT (reason, SingletonStrT { value = OrdinaryName "svg"; _ }) -> TypeCollector.add normalization_cx.type_collector (DefT (reason, RendersT (InstrinsicRenders "svg"))) diff --git a/src/typing/object_kit.ml b/src/typing/object_kit.ml index a0a0d078685..04ace95ef91 100644 --- a/src/typing/object_kit.ml +++ b/src/typing/object_kit.ml @@ -68,7 +68,7 @@ module Kit (Flow : Flow_common.S) : OBJECT = struct (fun (keys, indexers) t -> match t with | DefT (r, StrT_UNSOUND (_, name)) - | DefT (r, SingletonStrT name) -> + | DefT (r, SingletonStrT { value = name; _ }) -> ((name, r) :: keys, indexers) | DefT (_, EmptyT) -> (keys, indexers) | _ -> (keys, t :: indexers)) diff --git a/src/typing/predicate_kit.ml b/src/typing/predicate_kit.ml index f07f7e8f3a9..1a66cbf19e5 100644 --- a/src/typing/predicate_kit.ml +++ b/src/typing/predicate_kit.ml @@ -545,16 +545,16 @@ and intersect = * handling a few cases here explicitly. *) let ground_types_differ t1 t2 = match (C.unwrap t1, C.unwrap t2) with - | ( DefT (_, (SingletonStrT v1 | StrT_UNSOUND (_, v1))), - DefT (_, (SingletonStrT v2 | StrT_UNSOUND (_, v2))) + | ( DefT (_, (SingletonStrT { value = v1; _ } | StrT_UNSOUND (_, v1))), + DefT (_, (SingletonStrT { value = v2; _ } | StrT_UNSOUND (_, v2))) ) -> v1 <> v2 - | ( DefT (_, (SingletonNumT v1 | NumT_UNSOUND (_, v1))), - DefT (_, (SingletonNumT v2 | NumT_UNSOUND (_, v2))) + | ( DefT (_, (SingletonNumT { value = v1; _ } | NumT_UNSOUND (_, v1))), + DefT (_, (SingletonNumT { value = v2; _ } | NumT_UNSOUND (_, v2))) ) -> v1 <> v2 - | ( DefT (_, (SingletonBoolT v1 | BoolT_UNSOUND v1)), - DefT (_, (SingletonBoolT v2 | BoolT_UNSOUND v2)) + | ( DefT (_, (SingletonBoolT { value = v1; _ } | BoolT_UNSOUND v1)), + DefT (_, (SingletonBoolT { value = v2; _ } | BoolT_UNSOUND v2)) ) -> v1 <> v2 | (_, _) -> false @@ -1146,16 +1146,16 @@ and sentinel_prop_test_generic key cx trace result_collector orig_obj = in let sentinel_of_literal = function | DefT (_, StrT_UNSOUND (_, value)) - | DefT (_, SingletonStrT value) -> + | DefT (_, SingletonStrT { value; _ }) -> Some UnionEnum.(One (Str value)) | DefT (_, NumT_UNSOUND (_, value)) - | DefT (_, SingletonNumT value) -> + | DefT (_, SingletonNumT { value; _ }) -> Some UnionEnum.(One (Num value)) | DefT (_, BoolT_UNSOUND value) - | DefT (_, SingletonBoolT value) -> + | DefT (_, SingletonBoolT { value; _ }) -> Some UnionEnum.(One (Bool value)) | DefT (_, BigIntT_UNSOUND (_, value)) - | DefT (_, SingletonBigIntT value) -> + | DefT (_, SingletonBigIntT { value; _ }) -> Some UnionEnum.(One (BigInt value)) | DefT (_, VoidT) -> Some UnionEnum.(One Void) | DefT (_, NullT) -> Some UnionEnum.(One Null) @@ -1223,10 +1223,10 @@ and concretize_and_run_sentinel_prop_test | UnionEnum.One enum -> let def = match enum with - | UnionEnum.Str v -> SingletonStrT v - | UnionEnum.Num v -> SingletonNumT v - | UnionEnum.Bool v -> SingletonBoolT v - | UnionEnum.BigInt v -> SingletonBigIntT v + | UnionEnum.Str v -> SingletonStrT { from_annot = true; value = v } + | UnionEnum.Num v -> SingletonNumT { from_annot = true; value = v } + | UnionEnum.Bool v -> SingletonBoolT { from_annot = true; value = v } + | UnionEnum.BigInt v -> SingletonBigIntT { from_annot = true; value = v } | UnionEnum.Void -> VoidT | UnionEnum.Null -> NullT in @@ -1258,10 +1258,10 @@ and concretize_and_run_sentinel_prop_test (fun enum acc -> let def = match enum with - | UnionEnum.Str v -> SingletonStrT v - | UnionEnum.Num v -> SingletonNumT v - | UnionEnum.Bool v -> SingletonBoolT v - | UnionEnum.BigInt v -> SingletonBigIntT v + | UnionEnum.Str v -> SingletonStrT { from_annot = true; value = v } + | UnionEnum.Num v -> SingletonNumT { from_annot = true; value = v } + | UnionEnum.Bool v -> SingletonBoolT { from_annot = true; value = v } + | UnionEnum.BigInt v -> SingletonBigIntT { from_annot = true; value = v } | UnionEnum.Void -> VoidT | UnionEnum.Null -> NullT in @@ -1311,7 +1311,7 @@ and eq_test cx _trace result_collector (sense, left, right) = let expected_loc = loc_of_t right in match right with | DefT (_, StrT_UNSOUND (_, value)) - | DefT (_, SingletonStrT value) -> + | DefT (_, SingletonStrT { value; _ }) -> let filtered = if sense then Type_filter.string_literal cx expected_loc sense value left @@ -1320,7 +1320,7 @@ and eq_test cx _trace result_collector (sense, left, right) = in report_filtering_result_to_predicate_result filtered result_collector | DefT (_, NumT_UNSOUND (_, value)) - | DefT (_, SingletonNumT value) -> + | DefT (_, SingletonNumT { value; _ }) -> let filtered = if sense then Type_filter.number_literal cx expected_loc sense value left @@ -1329,7 +1329,7 @@ and eq_test cx _trace result_collector (sense, left, right) = in report_filtering_result_to_predicate_result filtered result_collector | DefT (_, BoolT_UNSOUND true) - | DefT (_, SingletonBoolT true) -> + | DefT (_, SingletonBoolT { value = true; _ }) -> let filtered = if sense then Type_filter.true_ cx left @@ -1338,7 +1338,7 @@ and eq_test cx _trace result_collector (sense, left, right) = in report_filtering_result_to_predicate_result filtered result_collector | DefT (_, BoolT_UNSOUND false) - | DefT (_, SingletonBoolT false) -> + | DefT (_, SingletonBoolT { value = false; _ }) -> let filtered = if sense then Type_filter.false_ cx left @@ -1347,7 +1347,7 @@ and eq_test cx _trace result_collector (sense, left, right) = in report_filtering_result_to_predicate_result filtered result_collector | DefT (_, BigIntT_UNSOUND (_, value)) - | DefT (_, SingletonBigIntT value) -> + | DefT (_, SingletonBigIntT { value; _ }) -> let filtered = if sense then Type_filter.bigint_literal cx expected_loc sense value left diff --git a/src/typing/react_kit.ml b/src/typing/react_kit.ml index e84cdff3a70..16d911d2d32 100644 --- a/src/typing/react_kit.ml +++ b/src/typing/react_kit.ml @@ -270,7 +270,7 @@ module Kit (Flow : Flow_common.S) : REACT = struct Flow_intermediate_error_types.ReactModuleForReactRefSetterType [instance] |> Option.some - | DefT (_, SingletonStrT name) -> + | DefT (_, SingletonStrT { value = name; _ }) -> let instance = Tvar_resolver.mk_tvar_and_fully_resolve_where cx reason_ref (fun tout -> get_intrinsic @@ -335,7 +335,7 @@ module Kit (Flow : Flow_common.S) : REACT = struct err_incompatible cx ~use_op:unknown_use r (React.GetProps tout); rec_flow_t ~use_op:unknown_use cx trace (AnyT.error reason_op, tout)) (* Special case for intrinsic components. *) - | DefT (_, SingletonStrT name) -> + | DefT (_, SingletonStrT { value = name; _ }) -> get_intrinsic cx trace @@ -497,7 +497,7 @@ module Kit (Flow : Flow_common.S) : REACT = struct (* Abstract components. *) | DefT (reason, ReactAbstractComponentT _) -> rec_flow_t ~use_op:unknown_use cx trace (tin, MixedT.why reason) (* Intrinsic components. *) - | DefT (_, SingletonStrT name) -> + | DefT (_, SingletonStrT { value = name; _ }) -> get_intrinsic ~artifact:`Props ~literal:(`Literal name) ~prop_polarity:Polarity.Negative tin | DefT (_, StrGeneralT gen) -> get_intrinsic ~artifact:`Props ~literal:(`General gen) ~prop_polarity:Polarity.Negative tin @@ -539,7 +539,7 @@ module Kit (Flow : Flow_common.S) : REACT = struct (not (Flow_js_utils.TvarVisitors.has_unresolved_tvars cx props)) && speculative_subtyping_succeeds cx - (DefT (r, SingletonStrT (OrdinaryName "ref"))) + (DefT (r, SingletonStrT { from_annot = false; value = OrdinaryName "ref" })) (KeysT (r, props)) in (* Create a type variable for our props. *) @@ -901,7 +901,7 @@ module Kit (Flow : Flow_common.S) : REACT = struct | DefT (r, ReactAbstractComponentT { instance = ComponentInstanceOmitted _; _ }) -> rec_flow_t ~use_op:unknown_use cx trace (VoidT.make (replace_desc_reason RVoid r), tout) (* Intrinsic components. *) - | DefT (_, SingletonStrT name) -> + | DefT (_, SingletonStrT { value = name; _ }) -> get_intrinsic ~artifact:`Instance ~literal:(`Literal name) diff --git a/src/typing/renders_kit.ml b/src/typing/renders_kit.ml index fe977cdf56d..1d08e045e79 100644 --- a/src/typing/renders_kit.ml +++ b/src/typing/renders_kit.ml @@ -249,7 +249,9 @@ module Make (Flow : INPUT) : S = struct speculative_subtyping_succeeds cx component_t - (DefT (elem_reason, SingletonStrT (Reason.OrdinaryName "svg"))) + (DefT + (elem_reason, SingletonStrT { from_annot = true; value = Reason.OrdinaryName "svg" }) + ) then ([DefT (elem_reason, RendersT (InstrinsicRenders "svg"))], false) else @@ -282,7 +284,7 @@ module Make (Flow : INPUT) : S = struct let non_renders_to_renders cx trace ~use_op l (renders_r, upper_renders) = match (l, upper_renders) with - | ( DefT (_, (NullT | VoidT | BoolT_UNSOUND false | SingletonBoolT false)), + | ( DefT (_, (NullT | VoidT | BoolT_UNSOUND false | SingletonBoolT { value = false; _ })), ( StructuralRenders { renders_variant = RendersMaybe | RendersStar; renders_structural_type = _ } | DefaultRenders ) @@ -405,7 +407,7 @@ module Make (Flow : INPUT) : S = struct FailedSynthesisState else on_concretized_react_node_types cx ~drop_renders_any ~state ts - | DefT (_, (NullT | VoidT | BoolT_UNSOUND false | SingletonBoolT false)) -> + | DefT (_, (NullT | VoidT | BoolT_UNSOUND false | SingletonBoolT { value = false; _ })) -> let renders_variant = merge_renders_variant (renders_variant, RendersMaybe) in IntermediateSynthesisState { normalized_render_type_collector; renders_variant } | DefT (_, ArrT (ArrayAT { elem_t = t; _ } | TupleAT { elem_t = t; _ } | ROArrayAT (t, _))) diff --git a/src/typing/slice_utils.ml b/src/typing/slice_utils.ml index ff5ec68e01c..2fc7ebdc0d3 100644 --- a/src/typing/slice_utils.ml +++ b/src/typing/slice_utils.ml @@ -1854,7 +1854,12 @@ let map_object | None -> loc_of_reason (reason_of_t prop_t) | Some loc -> loc in - let key_t = DefT (mk_reason (RStringLit key) key_loc, SingletonStrT key) in + let key_t = + DefT + ( mk_reason (RStringLit key) key_loc, + SingletonStrT { from_annot = true; value = key } + ) + in let prop_optional = is_prop_optional prop_t in let polarity = if frozen then diff --git a/src/typing/statement.ml b/src/typing/statement.ml index 25b5c0545f6..d2e269f1983 100644 --- a/src/typing/statement.ml +++ b/src/typing/statement.ml @@ -771,7 +771,7 @@ module Make Type_hint.with_hint_result hint ~ok:Base.Fn.id ~error else if singleton then let reason = mk_annot_reason (RStringLit (OrdinaryName value)) loc in - DefT (reason, SingletonStrT (OrdinaryName value)) + DefT (reason, SingletonStrT { from_annot = true; value = OrdinaryName value }) else (* It's too expensive to track literal information for large strings.*) let max_literal_length = Context.max_literal_length cx in @@ -788,7 +788,7 @@ module Make let boolean_literal ~singleton loc { Ast.BooleanLiteral.value; _ } = if singleton then let reason = mk_annot_reason (RBooleanLit value) loc in - DefT (reason, SingletonBoolT value) + DefT (reason, SingletonBoolT { from_annot = true; value }) else let reason = mk_annot_reason RBoolean loc in DefT (reason, BoolT_UNSOUND value) @@ -798,7 +798,7 @@ module Make let number_literal ~singleton loc { Ast.NumberLiteral.value; raw; _ } = if singleton then let reason = mk_annot_reason (RNumberLit raw) loc in - DefT (reason, SingletonNumT (value, raw)) + DefT (reason, SingletonNumT { from_annot = true; value = (value, raw) }) else let reason = mk_annot_reason RNumber loc in DefT (reason, NumT_UNSOUND (None, (value, raw))) @@ -806,7 +806,7 @@ module Make let bigint_literal ~singleton loc { Ast.BigIntLiteral.value; raw; _ } = if singleton then let reason = mk_annot_reason (RBigIntLit raw) loc in - DefT (reason, SingletonBigIntT (value, raw)) + DefT (reason, SingletonBigIntT { from_annot = true; value = (value, raw) }) else let reason = mk_annot_reason RBigInt loc in DefT (reason, BigIntT_UNSOUND (None, (value, raw))) @@ -4972,9 +4972,9 @@ module Make make a negative number not look like a literal.) *) let (reason, lit) = Flow_js_utils.unary_negate_lit ~annot_loc:loc reason lit in DefT (reason, NumT_UNSOUND (sense, lit)) - | DefT (reason, SingletonNumT lit) -> + | DefT (reason, SingletonNumT { from_annot; value = lit }) -> let (reason, lit) = Flow_js_utils.unary_negate_lit ~annot_loc:loc reason lit in - DefT (reason, SingletonNumT lit) + DefT (reason, SingletonNumT { from_annot; value = lit }) | arg -> let reason = mk_reason (desc_of_t arg) loc in Operators.unary_arith cx reason UnaryArithKind.Minus arg @@ -5797,7 +5797,7 @@ module Make let reason = mk_reason (RIdentifier (OrdinaryName name)) loc in TypeAssertions.assert_non_component_like_base cx def_loc reason t ); - let strt = SingletonStrT (OrdinaryName name) in + let strt = SingletonStrT { from_annot = true; value = OrdinaryName name } in DefT (mk_reason (RIdentifier (OrdinaryName name)) loc, strt) end in diff --git a/src/typing/subtyping_kit.ml b/src/typing/subtyping_kit.ml index fbda9b69454..fd285b4f7b4 100644 --- a/src/typing/subtyping_kit.ml +++ b/src/typing/subtyping_kit.ml @@ -1012,14 +1012,15 @@ module Make (Flow : INPUT) : OUTPUT = struct DefT (_, (NumGeneralT _ | NumT_UNSOUND _ | StrGeneralT _ | StrT_UNSOUND _)) ) -> () - | (DefT (rl, NumericStrKeyT (actual, _)), DefT (ru, SingletonNumT (expected, _))) -> + | (DefT (rl, NumericStrKeyT (actual, _)), DefT (ru, SingletonNumT { value = (expected, _); _ })) + -> if actual = expected then () else add_output cx (Error_message.EExpectedNumberLit { reason_lower = rl; reason_upper = ru; use_op }) - | (DefT (rl, NumericStrKeyT (_, actual)), DefT (ru, SingletonStrT expected)) -> + | (DefT (rl, NumericStrKeyT (_, actual)), DefT (ru, SingletonStrT { value = expected; _ })) -> if OrdinaryName actual = expected then () else @@ -1052,8 +1053,8 @@ module Make (Flow : INPUT) : OUTPUT = struct * necessity we allow all string types to flow to StrT_UNSOUND (whereas only * exactly matching string literal types may flow to SingletonStrT). * *) - | ( DefT (rl, (StrT_UNSOUND (_, actual) | SingletonStrT actual)), - DefT (ru, SingletonStrT expected) + | ( DefT (rl, (StrT_UNSOUND (_, actual) | SingletonStrT { value = actual; _ })), + DefT (ru, SingletonStrT { value = expected; _ }) ) -> if expected = actual then () @@ -1069,8 +1070,8 @@ module Make (Flow : INPUT) : OUTPUT = struct add_output cx (Error_message.EExpectedStringLit { reason_lower = rl; reason_upper = ru; use_op }) - | ( DefT (rl, (NumT_UNSOUND (_, (actual, _)) | SingletonNumT (actual, _))), - DefT (ru, SingletonNumT (expected, _)) + | ( DefT (rl, (NumT_UNSOUND (_, (actual, _)) | SingletonNumT { value = (actual, _); _ })), + DefT (ru, SingletonNumT { value = (expected, _); _ }) ) -> if expected = actual then () @@ -1086,8 +1087,9 @@ module Make (Flow : INPUT) : OUTPUT = struct add_output cx (Error_message.EExpectedNumberLit { reason_lower = rl; reason_upper = ru; use_op }) - | (DefT (rl, (BoolT_UNSOUND actual | SingletonBoolT actual)), DefT (ru, SingletonBoolT expected)) - -> + | ( DefT (rl, (BoolT_UNSOUND actual | SingletonBoolT { value = actual; _ })), + DefT (ru, SingletonBoolT { value = expected; _ }) + ) -> if expected = actual then () else @@ -1102,8 +1104,8 @@ module Make (Flow : INPUT) : OUTPUT = struct add_output cx (Error_message.EExpectedBooleanLit { reason_lower = rl; reason_upper = ru; use_op }) - | ( DefT (rl, (BigIntT_UNSOUND (_, (actual, _)) | SingletonBigIntT (actual, _))), - DefT (ru, SingletonBigIntT (expected, _)) + | ( DefT (rl, (BigIntT_UNSOUND (_, (actual, _)) | SingletonBigIntT { value = (actual, _); _ })), + DefT (ru, SingletonBigIntT { value = (expected, _); _ }) ) -> if expected = actual then () @@ -1122,9 +1124,13 @@ module Make (Flow : INPUT) : OUTPUT = struct (*****************************************************) (* keys (NOTE: currently we only support string keys *) (*****************************************************) - | ( ( DefT (reason_s, (StrT_UNSOUND (_, x) | SingletonStrT x)) + | ( ( DefT (reason_s, (StrT_UNSOUND (_, x) | SingletonStrT { value = x; _ })) | GenericT - { reason = reason_s; bound = DefT (_, (StrT_UNSOUND (_, x) | SingletonStrT x)); _ } ), + { + reason = reason_s; + bound = DefT (_, (StrT_UNSOUND (_, x) | SingletonStrT { value = x; _ })); + _; + } ), KeysT (reason_op, o) ) -> let reason_next = replace_desc_new_reason (RProperty (Some x)) reason_s in @@ -1244,9 +1250,9 @@ module Make (Flow : INPUT) : OUTPUT = struct in begin match u with - | DefT (_, (StrT_UNSOUND (_, x) | SingletonStrT x)) -> check (UnionEnum.Str x) - | DefT (_, (BoolT_UNSOUND x | SingletonBoolT x)) -> check (UnionEnum.Bool x) - | DefT (_, (NumT_UNSOUND (_, x) | SingletonNumT x)) -> check (UnionEnum.Num x) + | DefT (_, (StrT_UNSOUND (_, x) | SingletonStrT { value = x; _ })) -> check (UnionEnum.Str x) + | DefT (_, (BoolT_UNSOUND x | SingletonBoolT { value = x; _ })) -> check (UnionEnum.Bool x) + | DefT (_, (NumT_UNSOUND (_, x) | SingletonNumT { value = x; _ })) -> check (UnionEnum.Num x) | _ -> flow_all_in_union cx trace rep (UseT (use_op, u)) end | (_, IntersectionT (_, rep)) -> @@ -1259,7 +1265,9 @@ module Make (Flow : INPUT) : OUTPUT = struct (* String enum sets can be handled in logarithmic time by just * checking for membership in the set. *) - | (DefT (reason_l, (StrT_UNSOUND (_, x) | SingletonStrT x)), UnionT (reason_u, rep)) + | ( DefT (reason_l, (StrT_UNSOUND (_, x) | SingletonStrT { value = x; _ })), + UnionT (reason_u, rep) + ) when match UnionRep.check_enum rep with | Some enums -> if not (UnionEnumSet.mem (UnionEnum.Str x) enums) then @@ -1389,7 +1397,10 @@ module Make (Flow : INPUT) : OUTPUT = struct when prefix1 = prefix2 -> let remainder1 = Option.value ~default:(StrModuleT.why reason) remainder1 in rec_flow_t cx trace ~use_op (remainder1, remainder2) - | ( DefT (reason, (StrT_UNSOUND (None, OrdinaryName s) | SingletonStrT (OrdinaryName s))), + | ( DefT + ( reason, + (StrT_UNSOUND (None, OrdinaryName s) | SingletonStrT { value = OrdinaryName s; _ }) + ), StrUtilT { reason = _; op = StrPrefix prefix; remainder } ) when String.starts_with ~prefix s -> @@ -1411,7 +1422,10 @@ module Make (Flow : INPUT) : OUTPUT = struct when suffix1 = suffix2 -> let remainder1 = Option.value ~default:(StrModuleT.why reason) remainder1 in rec_flow_t cx trace ~use_op (remainder1, remainder2) - | ( DefT (reason, (StrT_UNSOUND (None, OrdinaryName s) | SingletonStrT (OrdinaryName s))), + | ( DefT + ( reason, + (StrT_UNSOUND (None, OrdinaryName s) | SingletonStrT { value = OrdinaryName s; _ }) + ), StrUtilT { reason = _; op = StrSuffix suffix; remainder } ) when String.ends_with ~suffix s -> diff --git a/src/typing/ty_normalizer.ml b/src/typing/ty_normalizer.ml index 39c407b9ac6..c48bf6b7527 100644 --- a/src/typing/ty_normalizer.ml +++ b/src/typing/ty_normalizer.ml @@ -814,10 +814,10 @@ module Make (I : INPUT) : S = struct | DefT (_, NullT) -> return Ty.Null | DefT (_, SymbolT) -> return Ty.Symbol | DefT (_, NumericStrKeyT (_, s)) -> return (Ty.StrLit (OrdinaryName s)) - | DefT (_, SingletonNumT (_, lit)) -> return (Ty.NumLit lit) - | DefT (_, SingletonStrT lit) -> return (Ty.StrLit lit) - | DefT (_, SingletonBoolT lit) -> return (Ty.BoolLit lit) - | DefT (_, SingletonBigIntT (_, lit)) -> return (Ty.BigIntLit lit) + | DefT (_, SingletonNumT { value = (_, lit); _ }) -> return (Ty.NumLit lit) + | DefT (_, SingletonStrT { value = lit; _ }) -> return (Ty.StrLit lit) + | DefT (_, SingletonBoolT { value = lit; _ }) -> return (Ty.BoolLit lit) + | DefT (_, SingletonBigIntT { value = (_, lit); _ }) -> return (Ty.BigIntLit lit) | StrUtilT { reason = _; op; remainder = None } -> return (Ty.Utility @@ -2549,9 +2549,9 @@ module Make (I : INPUT) : S = struct | MaybeT (_, t) -> maybe_t ~env ?id ~cont:type__ t | OptionalT { type_ = t; _ } -> optional_t ~env ?id ~cont:type__ t | KeysT (r, t) -> keys_t ~env ~cont:type__ r ~force_eval:true t - | DefT (_, SingletonNumT (_, lit)) -> return (Ty.NumLit lit) - | DefT (_, SingletonStrT lit) -> return (Ty.StrLit lit) - | DefT (_, SingletonBoolT lit) -> return (Ty.BoolLit lit) + | DefT (_, SingletonNumT { value = (_, lit); _ }) -> return (Ty.NumLit lit) + | DefT (_, SingletonStrT { value = lit; _ }) -> return (Ty.StrLit lit) + | DefT (_, SingletonBoolT { value = lit; _ }) -> return (Ty.BoolLit lit) | DefT (_, BoolGeneralT) | DefT (_, BoolT_UNSOUND _) -> return (Ty.Bool None) diff --git a/src/typing/type.ml b/src/typing/type.ml index 58afa8347c7..58514be26ee 100644 --- a/src/typing/type.ml +++ b/src/typing/type.ml @@ -202,8 +202,11 @@ module rec TypeTerm : sig (* type of an instance of a class *) | InstanceT of instance_t (* singleton string, matches exactly a given string literal *) - (* TODO SingletonStrT should not include internal names *) - | SingletonStrT of name + | SingletonStrT of { + from_annot: bool; + (* TODO SingletonStrT should not include internal names *) + value: name; + } (* This type is only to be used to represent numeric-like object keys in the context of object-to-object subtyping. It allows numeric-like object keys to be a subtype of both `number` and `string`, so that `{1: true}` can be @@ -215,10 +218,19 @@ module rec TypeTerm : sig | NumericStrKeyT of number_literal (* matches exactly a given number literal, for some definition of "exactly" when it comes to floats... *) - | SingletonNumT of number_literal + | SingletonNumT of { + from_annot: bool; + value: number_literal; + } (* singleton bool, matches exactly a given boolean literal *) - | SingletonBoolT of bool - | SingletonBigIntT of bigint_literal + | SingletonBoolT of { + from_annot: bool; + value: bool; + } + | SingletonBigIntT of { + from_annot: bool; + value: bigint_literal; + } (* type aliases *) | TypeT of type_t_kind * t (* A polymorphic type is like a type-level "function" that, when applied to @@ -2411,17 +2423,17 @@ end = struct let canon = TypeTerm.( function - | DefT (_, SingletonStrT lit) + | DefT (_, SingletonStrT { value = lit; _ }) | DefT (_, StrT_UNSOUND (_, lit)) -> Some (UnionEnum.Str lit) | DefT (_, NumericStrKeyT (_, s)) -> Some (UnionEnum.Str (OrdinaryName s)) - | DefT (_, SingletonNumT lit) + | DefT (_, SingletonNumT { value = lit; _ }) | DefT (_, NumT_UNSOUND (_, lit)) -> Some (UnionEnum.Num lit) - | DefT (_, SingletonBigIntT lit) + | DefT (_, SingletonBigIntT { value = lit; _ }) | DefT (_, BigIntT_UNSOUND (_, lit)) -> Some (UnionEnum.BigInt lit) - | DefT (_, SingletonBoolT lit) + | DefT (_, SingletonBoolT { value = lit; _ }) | DefT (_, BoolT_UNSOUND lit) -> Some (UnionEnum.Bool lit) | DefT (_, VoidT) -> Some UnionEnum.Void diff --git a/src/typing/typeUtil.ml b/src/typing/typeUtil.ml index a0c810db8e1..14c3967b723 100644 --- a/src/typing/typeUtil.ml +++ b/src/typing/typeUtil.ml @@ -465,14 +465,14 @@ let is_falsy = function | DefT ( _, ( NullT | VoidT - | SingletonBoolT false + | SingletonBoolT { value = false; _ } | BoolT_UNSOUND false | EnumValueT ( ConcreteEnum { representation_t = DefT (_, BoolT_UNSOUND false); _ } | AbstractEnum { representation_t = DefT (_, BoolT_UNSOUND false) } ) - | SingletonStrT (OrdinaryName "") + | SingletonStrT { value = OrdinaryName ""; _ } | StrT_UNSOUND (_, OrdinaryName "") - | SingletonNumT (0., _) + | SingletonNumT { value = (0., _); _ } | NumT_UNSOUND (_, (0., _)) ) ) -> true @@ -556,18 +556,23 @@ let quick_subtype t1 t2 = | (StrUtilT _, DefT (_, StrGeneralT AnyLiteral)) -> true | (l, DefT (_, MixedT mixed_flavor)) when is_mixed_subtype l mixed_flavor -> true | (DefT (_, StrGeneralT _), DefT (_, SingletonStrT _)) -> false - | (DefT (_, StrT_UNSOUND (_, actual)), DefT (_, SingletonStrT expected)) -> expected = actual + | (DefT (_, StrT_UNSOUND (_, actual)), DefT (_, SingletonStrT { value = expected; _ })) -> + expected = actual | (DefT (_, NumGeneralT _), DefT (_, SingletonNumT _)) -> false - | (DefT (_, NumT_UNSOUND (_, (actual, _))), DefT (_, SingletonNumT (expected, _))) -> + | (DefT (_, NumT_UNSOUND (_, (actual, _))), DefT (_, SingletonNumT { value = (expected, _); _ })) + -> expected = actual | (DefT (_, BigIntGeneralT _), DefT (_, SingletonBigIntT _)) -> false - | (DefT (_, BigIntT_UNSOUND (_, (actual, _))), DefT (_, SingletonBigIntT (expected, _))) -> + | ( DefT (_, BigIntT_UNSOUND (_, (actual, _))), + DefT (_, SingletonBigIntT { value = (expected, _); _ }) + ) -> expected = actual | (DefT (_, BoolGeneralT), DefT (_, SingletonBoolT _)) -> false - | (DefT (_, BoolT_UNSOUND actual), DefT (_, SingletonBoolT expected)) -> expected = actual - | (DefT (_, NumericStrKeyT (actual, _)), DefT (_, SingletonNumT (expected, _))) -> + | (DefT (_, BoolT_UNSOUND actual), DefT (_, SingletonBoolT { value = expected; _ })) -> + expected = actual + | (DefT (_, NumericStrKeyT (actual, _)), DefT (_, SingletonNumT { value = (expected, _); _ })) -> actual = expected - | (DefT (_, NumericStrKeyT (_, actual)), DefT (_, SingletonStrT expected)) -> + | (DefT (_, NumericStrKeyT (_, actual)), DefT (_, SingletonStrT { value = expected; _ })) -> OrdinaryName actual = expected | _ -> reasonless_eq t1 t2 @@ -824,7 +829,7 @@ let tuple_length reason ~inexact (num_req, num_total) = let t = let float = Base.Float.of_int n in let string = Base.Int.to_string n in - SingletonNumT (float, string) + SingletonNumT { from_annot = false; value = (float, string) } in DefT (r, t) in diff --git a/src/typing/type_annotation.ml b/src/typing/type_annotation.ml index 0ef91a5b1ff..1b98d5de8e4 100644 --- a/src/typing/type_annotation.ml +++ b/src/typing/type_annotation.ml @@ -753,7 +753,7 @@ module Make (Statement : Statement_sig.S) : Type_annotation_sig.S = struct let (ts, targs) = convert_type_params () in let create_string_prefix_type ~prefix ~remainder = match prefix with - | DefT (_, SingletonStrT (OrdinaryName prefix)) -> + | DefT (_, SingletonStrT { value = OrdinaryName prefix; _ }) -> let reason = mk_reason (RStringPrefix { prefix }) loc in reconstruct_ast (StrUtilT { reason; op = StrPrefix prefix; remainder }) targs | _ -> error_type cx loc (Error_message.EStrUtilTypeNonLiteralArg loc) t_ast @@ -778,7 +778,7 @@ module Make (Statement : Statement_sig.S) : Type_annotation_sig.S = struct let (ts, targs) = convert_type_params () in let create_string_suffix_type ~suffix ~remainder = match suffix with - | DefT (_, SingletonStrT (OrdinaryName suffix)) -> + | DefT (_, SingletonStrT { value = OrdinaryName suffix; _ }) -> let reason = mk_reason (RStringSuffix { suffix }) loc in reconstruct_ast (StrUtilT { reason; op = StrSuffix suffix; remainder }) targs | _ -> error_type cx loc (Error_message.EStrUtilTypeNonLiteralArg loc) t_ast @@ -825,7 +825,7 @@ module Make (Statement : Statement_sig.S) : Type_annotation_sig.S = struct | "$PropertyType" -> check_type_arg_arity cx loc t_ast targs 2 (fun () -> match convert_type_params () with - | ([t; DefT (_, SingletonStrT key)], targs) -> + | ([t; DefT (_, SingletonStrT { value = key; _ })], targs) -> let reason = mk_reason (RType (OrdinaryName "$PropertyType")) loc in reconstruct_ast (mk_type_destructor @@ -2606,19 +2606,19 @@ module Make (Statement : Statement_sig.S) : Type_annotation_sig.S = struct and mk_singleton_string loc key = let reason = mk_annot_reason (RStringLit (OrdinaryName key)) loc in - DefT (reason, SingletonStrT (OrdinaryName key)) + DefT (reason, SingletonStrT { from_annot = true; value = OrdinaryName key }) and mk_singleton_number loc num raw = let reason = mk_annot_reason (RNumberLit raw) loc in - DefT (reason, SingletonNumT (num, raw)) + DefT (reason, SingletonNumT { from_annot = true; value = (num, raw) }) and mk_singleton_boolean loc b = let reason = mk_annot_reason (RBooleanLit b) loc in - DefT (reason, SingletonBoolT b) + DefT (reason, SingletonBoolT { from_annot = true; value = b }) and mk_singleton_bigint loc num raw = let reason = mk_annot_reason (RBigIntLit raw) loc in - DefT (reason, SingletonBigIntT (num, raw)) + DefT (reason, SingletonBigIntT { from_annot = true; value = (num, raw) }) (* Given the type of expression C and type arguments T1...Tn, return the type of values described by C, or C when there are no type arguments. *) diff --git a/src/typing/type_filter.ml b/src/typing/type_filter.ml index 3b0923cb3f2..d1866e74355 100644 --- a/src/typing/type_filter.ml +++ b/src/typing/type_filter.ml @@ -273,17 +273,18 @@ let mk_str_literal cx expected = if Context.allow_unsound_literal_coercsion cx then StrT_UNSOUND (None, expected) else - SingletonStrT expected + SingletonStrT { from_annot = false; value = expected } let string_literal cx expected_loc sense expected t = let expected_desc = RStringLit expected in let lit_reason = replace_desc_new_reason expected_desc in match t with - | DefT (_, SingletonStrT actual) -> + | DefT (_, SingletonStrT { from_annot; value = actual }) -> if actual = expected then unchanged_result t else - DefT (mk_reason expected_desc expected_loc, SingletonStrT expected) |> changed_result + DefT (mk_reason expected_desc expected_loc, SingletonStrT { from_annot; value = expected }) + |> changed_result | DefT (_, StrT_UNSOUND (_, actual)) -> if actual = expected then unchanged_result t @@ -300,7 +301,7 @@ let string_literal cx expected_loc sense expected t = | _ -> DefT (reason_of_t t, EmptyT) |> changed_result let not_string_literal expected = function - | DefT (r, SingletonStrT actual) + | DefT (r, SingletonStrT { value = actual; _ }) | DefT (r, StrT_UNSOUND (_, actual)) when actual = expected -> DefT (r, EmptyT) |> changed_result @@ -310,18 +311,19 @@ let mk_num_literal cx expected = if Context.allow_unsound_literal_coercsion cx then NumT_UNSOUND (None, expected) else - SingletonNumT expected + SingletonNumT { from_annot = false; value = expected } let number_literal cx expected_loc sense expected t = let (_, expected_raw) = expected in let expected_desc = RNumberLit expected_raw in let lit_reason = replace_desc_new_reason expected_desc in match t with - | DefT (_, SingletonNumT (_, actual_raw)) -> + | DefT (_, SingletonNumT { from_annot; value = (_, actual_raw) }) -> if actual_raw = expected_raw then unchanged_result t else - DefT (mk_reason expected_desc expected_loc, SingletonNumT expected) |> changed_result + DefT (mk_reason expected_desc expected_loc, SingletonNumT { from_annot; value = expected }) + |> changed_result | DefT (_, NumT_UNSOUND (_, (_, actual_raw))) -> if actual_raw = expected_raw then unchanged_result t @@ -337,7 +339,7 @@ let number_literal cx expected_loc sense expected t = | _ -> DefT (reason_of_t t, EmptyT) |> changed_result let not_number_literal expected = function - | DefT (r, SingletonNumT actual) + | DefT (r, SingletonNumT { value = actual; _ }) | DefT (r, NumT_UNSOUND (_, actual)) when snd actual = snd expected -> DefT (r, EmptyT) |> changed_result @@ -347,18 +349,19 @@ let mk_bigint_literal cx expected = if Context.allow_unsound_literal_coercsion cx then BigIntT_UNSOUND (None, expected) else - SingletonBigIntT expected + SingletonBigIntT { from_annot = false; value = expected } let bigint_literal cx expected_loc sense expected t = let (_, expected_raw) = expected in let expected_desc = RBigIntLit expected_raw in let lit_reason = replace_desc_new_reason expected_desc in match t with - | DefT (_, SingletonBigIntT (_, actual_raw)) -> + | DefT (_, SingletonBigIntT { from_annot; value = (_, actual_raw) }) -> if actual_raw = expected_raw then unchanged_result t else - DefT (mk_reason expected_desc expected_loc, SingletonBigIntT expected) |> changed_result + DefT (mk_reason expected_desc expected_loc, SingletonBigIntT { from_annot; value = expected }) + |> changed_result | DefT (_, BigIntT_UNSOUND (_, (_, actual_raw))) -> if actual_raw = expected_raw then unchanged_result t @@ -374,7 +377,7 @@ let bigint_literal cx expected_loc sense expected t = | _ -> DefT (reason_of_t t, EmptyT) |> changed_result let not_bigint_literal expected = function - | DefT (r, SingletonBigIntT actual) + | DefT (r, SingletonBigIntT { value = actual; _ }) | DefT (r, BigIntT_UNSOUND (_, actual)) when snd actual = snd expected -> DefT (r, EmptyT) |> changed_result @@ -384,12 +387,13 @@ let mk_bool_literal cx expected = if Context.allow_unsound_literal_coercsion cx then BoolT_UNSOUND expected else - SingletonBoolT expected + SingletonBoolT { from_annot = false; value = expected } let true_ cx t = let lit_reason = replace_desc_new_reason (RBooleanLit true) in match t with - | DefT (r, SingletonBoolT true) -> DefT (lit_reason r, SingletonBoolT true) |> unchanged_result + | DefT (r, SingletonBoolT { from_annot; value = true }) -> + DefT (lit_reason r, SingletonBoolT { from_annot; value = true }) |> unchanged_result | DefT (r, BoolT_UNSOUND true) -> DefT (lit_reason r, BoolT_UNSOUND true) |> unchanged_result | DefT (r, BoolGeneralT) -> DefT (lit_reason r, mk_bool_literal cx true) |> changed_result | DefT (r, MixedT _) -> DefT (lit_reason r, mk_bool_literal cx true) |> changed_result @@ -399,7 +403,7 @@ let true_ cx t = let not_true cx t = let lit_reason = replace_desc_new_reason (RBooleanLit false) in match t with - | DefT (r, SingletonBoolT true) + | DefT (r, SingletonBoolT { value = true; _ }) | DefT (r, BoolT_UNSOUND true) -> DefT (r, EmptyT) |> changed_result | DefT (r, BoolGeneralT) -> DefT (lit_reason r, mk_bool_literal cx false) |> changed_result @@ -408,7 +412,8 @@ let not_true cx t = let false_ cx t = let lit_reason = replace_desc_new_reason (RBooleanLit false) in match t with - | DefT (r, SingletonBoolT false) -> DefT (lit_reason r, SingletonBoolT false) |> unchanged_result + | DefT (r, SingletonBoolT { from_annot; value = false }) -> + DefT (lit_reason r, SingletonBoolT { from_annot; value = false }) |> unchanged_result | DefT (r, BoolT_UNSOUND false) -> DefT (lit_reason r, BoolT_UNSOUND false) |> unchanged_result | DefT (r, BoolGeneralT) -> DefT (lit_reason r, mk_bool_literal cx false) |> changed_result | DefT (r, MixedT _) -> DefT (lit_reason r, mk_bool_literal cx false) |> changed_result @@ -418,7 +423,7 @@ let false_ cx t = let not_false cx t = let lit_reason = replace_desc_new_reason (RBooleanLit true) in match t with - | DefT (r, SingletonBoolT false) + | DefT (r, SingletonBoolT { value = false; _ }) | DefT (r, BoolT_UNSOUND false) -> DefT (r, EmptyT) |> changed_result | DefT (r, BoolGeneralT) -> DefT (lit_reason r, mk_bool_literal cx true) |> changed_result @@ -742,19 +747,19 @@ let array_length ~sense ~op ~n t = let sentinel_refinement = let open UnionEnum in let enum_match sense = function - | (DefT (_, SingletonStrT value), Str sentinel) + | (DefT (_, SingletonStrT { value; _ }), Str sentinel) | (DefT (_, StrT_UNSOUND (_, value)), Str sentinel) when value = sentinel != sense -> true - | (DefT (_, SingletonNumT (value, _)), Num (sentinel, _)) + | (DefT (_, SingletonNumT { value = (value, _); _ }), Num (sentinel, _)) | (DefT (_, NumT_UNSOUND (_, (value, _))), Num (sentinel, _)) when value = sentinel != sense -> true - | (DefT (_, SingletonBoolT value), Bool sentinel) + | (DefT (_, SingletonBoolT { value; _ }), Bool sentinel) | (DefT (_, BoolT_UNSOUND value), Bool sentinel) when value = sentinel != sense -> true - | (DefT (_, SingletonBigIntT (value, _)), BigInt (sentinel, _)) + | (DefT (_, SingletonBigIntT { value = (value, _); _ }), BigInt (sentinel, _)) | (DefT (_, BigIntT_UNSOUND (_, (value, _))), BigInt (sentinel, _)) when value = sentinel != sense -> true @@ -887,9 +892,9 @@ module TypeTagSet : Flow_set.S with type elt = TypeTag.t = Flow_set.Make (TypeTa let tag_of_value cx type_ = match Context.find_resolved cx type_ with | Some (DefT (_, NumericStrKeyT (_, s))) -> Some (TypeTag.Str (OrdinaryName s)) - | Some (DefT (_, SingletonStrT name)) -> Some (TypeTag.Str name) - | Some (DefT (_, SingletonNumT num_lit)) -> Some (TypeTag.Num num_lit) - | Some (DefT (_, SingletonBoolT b)) -> Some (TypeTag.Bool b) + | Some (DefT (_, SingletonStrT { value = name; _ })) -> Some (TypeTag.Str name) + | Some (DefT (_, SingletonNumT { value = num_lit; _ })) -> Some (TypeTag.Num num_lit) + | Some (DefT (_, SingletonBoolT { value = b; _ })) -> Some (TypeTag.Bool b) | _ -> None let sentinel_of_obj cx id = diff --git a/src/typing/type_hint.ml b/src/typing/type_hint.ml index ff22a736146..4d65a069518 100644 --- a/src/typing/type_hint.ml +++ b/src/typing/type_hint.ml @@ -597,10 +597,16 @@ and type_of_hint_decomposition cx op reason t = let predicate_of_check (prop, literal_check) = let other_t = match literal_check with - | SingletonBool b -> DefT (reason, SingletonBoolT b) - | SingletonNum n -> DefT (reason, SingletonNumT (n, string_of_float n)) - | SingletonStr s -> DefT (reason, SingletonStrT (OrdinaryName s)) - | SingletonBigInt n -> DefT (reason, SingletonBigIntT (Some n, Int64.to_string n)) + | SingletonBool b -> DefT (reason, SingletonBoolT { from_annot = true; value = b }) + | SingletonNum n -> + DefT (reason, SingletonNumT { from_annot = true; value = (n, string_of_float n) }) + | SingletonStr s -> + DefT (reason, SingletonStrT { from_annot = true; value = OrdinaryName s }) + | SingletonBigInt n -> + DefT + ( reason, + SingletonBigIntT { from_annot = true; value = (Some n, Int64.to_string n) } + ) | Member reason -> Type_env.find_write cx Env_api.ExpressionLoc reason in BinaryP (SentinelProp prop, other_t) diff --git a/src/typing/type_operation_utils.ml b/src/typing/type_operation_utils.ml index 51d1ca13bbf..861bd580acb 100644 --- a/src/typing/type_operation_utils.ml +++ b/src/typing/type_operation_utils.ml @@ -449,11 +449,11 @@ module Operators = struct BoolModuleT.at (loc_of_reason reason) (* !x when x is falsy *) | DefT (_, BoolT_UNSOUND false) - | DefT (_, SingletonBoolT false) + | DefT (_, SingletonBoolT { value = false; _ }) | DefT (_, StrT_UNSOUND (_, OrdinaryName "")) - | DefT (_, SingletonStrT (OrdinaryName "")) + | DefT (_, SingletonStrT { value = OrdinaryName ""; _ }) | DefT (_, NumT_UNSOUND (_, (0., _))) - | DefT (_, SingletonNumT (0., _)) + | DefT (_, SingletonNumT { value = (0., _); _ }) | DefT (_, NullT) | DefT (_, VoidT) -> let reason = replace_desc_reason (RBooleanLit true) reason in diff --git a/src/typing/type_sig_merge.ml b/src/typing/type_sig_merge.ml index ea9b583ce1b..b6ec49f7078 100644 --- a/src/typing/type_sig_merge.ml +++ b/src/typing/type_sig_merge.ml @@ -633,16 +633,16 @@ and merge_annot env file = function Type.(DefT (reason, ArrT (ROArrayAT (t, None)))) | SingletonString (loc, str) -> let reason = Reason.(mk_annot_reason (RStringLit (OrdinaryName str)) loc) in - Type.(DefT (reason, SingletonStrT (Reason.OrdinaryName str))) + Type.(DefT (reason, SingletonStrT { from_annot = true; value = Reason.OrdinaryName str })) | SingletonNumber (loc, num, raw) -> let reason = Reason.(mk_annot_reason (RNumberLit raw) loc) in - Type.(DefT (reason, SingletonNumT (num, raw))) + Type.(DefT (reason, SingletonNumT { from_annot = true; value = (num, raw) })) | SingletonBigInt (loc, bigint, raw) -> let reason = Reason.(mk_annot_reason (RBigIntLit raw) loc) in - Type.(DefT (reason, SingletonBigIntT (bigint, raw))) + Type.(DefT (reason, SingletonBigIntT { from_annot = true; value = (bigint, raw) })) | SingletonBoolean (loc, b) -> let reason = Reason.(mk_annot_reason (RBooleanLit b) loc) in - Type.(DefT (reason, SingletonBoolT b)) + Type.(DefT (reason, SingletonBoolT { from_annot = true; value = b })) | StringPrefix { loc; prefix; remainder } -> let reason = Reason.(mk_reason (RStringPrefix { prefix }) loc) in let remainder = Base.Option.map ~f:(merge env file) remainder in @@ -1138,7 +1138,7 @@ and merge_value ?(as_const = false) ?(const_decl = false) env file = function | StringLit (loc, lit) -> if as_const || const_decl then let reason = Reason.(mk_annot_reason (RStringLit (OrdinaryName lit)) loc) in - Type.(DefT (reason, SingletonStrT (Reason.OrdinaryName lit))) + Type.(DefT (reason, SingletonStrT { from_annot = false; value = Reason.OrdinaryName lit })) else let reason = Reason.(mk_reason RString loc) in Type.(DefT (reason, StrGeneralT AnyLiteral)) @@ -1152,7 +1152,7 @@ and merge_value ?(as_const = false) ?(const_decl = false) env file = function | NumberLit (loc, num, raw) -> if as_const || const_decl then let reason = Reason.(mk_annot_reason (RNumberLit raw) loc) in - Type.(DefT (reason, SingletonNumT (num, raw))) + Type.(DefT (reason, SingletonNumT { from_annot = false; value = (num, raw) })) else let reason = Reason.(mk_reason RNumber loc) in Type.(DefT (reason, NumGeneralT AnyLiteral)) @@ -1162,7 +1162,7 @@ and merge_value ?(as_const = false) ?(const_decl = false) env file = function | BigIntLit (loc, bigint, raw) -> if as_const || const_decl then let reason = Reason.(mk_annot_reason (RBigIntLit raw) loc) in - Type.(DefT (reason, SingletonBigIntT (bigint, raw))) + Type.(DefT (reason, SingletonBigIntT { from_annot = false; value = (bigint, raw) })) else let reason = Reason.(mk_reason RBigInt loc) in Type.(DefT (reason, BigIntGeneralT AnyLiteral)) @@ -1172,7 +1172,7 @@ and merge_value ?(as_const = false) ?(const_decl = false) env file = function | BooleanLit (loc, lit) -> if as_const || const_decl then let reason = Reason.(mk_annot_reason (RBooleanLit lit) loc) in - Type.(DefT (reason, SingletonBoolT lit)) + Type.(DefT (reason, SingletonBoolT { from_annot = false; value = lit })) else let reason = Reason.(mk_reason RBoolean loc) in Type.(DefT (reason, BoolGeneralT))