diff --git a/src/typing/debug_js.ml b/src/typing/debug_js.ml index c83a142fd4e..498fdddbf6c 100644 --- a/src/typing/debug_js.ml +++ b/src/typing/debug_js.ml @@ -775,6 +775,7 @@ and dump_use_t_ (depth, tvars) cx t = p ~extra:(spf "%s, (%s, %s)" (kid ix) (string_of_reason preason) (tvar ptvar)) t | GetKeysT _ -> p t | GetValuesT _ -> p t + | GetDictValuesT _ -> p t | MatchPropT (use_op, _, prop, (preason, ptvar)) | GetPropT (use_op, _, _, prop, (preason, ptvar)) -> p diff --git a/src/typing/default_resolve.ml b/src/typing/default_resolve.ml index d8ed846f680..005224cb965 100644 --- a/src/typing/default_resolve.ml +++ b/src/typing/default_resolve.ml @@ -143,6 +143,7 @@ let rec default_resolve_touts ~flow cx loc u = | ArrRestT (_, _, _, t) -> resolve t | BecomeT { t; _ } -> resolve t + | GetDictValuesT (_, use) -> default_resolve_touts ~flow cx loc use | GetKeysT (_, use) -> default_resolve_touts ~flow cx loc use | HasOwnPropT _ -> () | GetValuesT (_, t) -> resolve t diff --git a/src/typing/flow_js.ml b/src/typing/flow_js.ml index 51c69dd30f4..4a0c94500bf 100644 --- a/src/typing/flow_js.ml +++ b/src/typing/flow_js.ml @@ -1565,6 +1565,28 @@ struct (* Any will always be ok *) | (AnyT (_, src), GetValuesT (reason, values)) -> rec_flow_t ~use_op:unknown_use cx trace (AnyT.why src reason, values) + (***********************************************) + (* Values of a dictionary - `mixed` otherwise. *) + (***********************************************) + | ( DefT + ( _, + _, + ObjT + { flags = { obj_kind = Indexed { value; dict_polarity; _ }; _ }; props_tmap; _ } + ), + GetDictValuesT (_, result) + ) + when Context.find_props cx props_tmap |> NameUtils.Map.is_empty + && Polarity.compat (dict_polarity, Polarity.Positive) -> + rec_flow cx trace (value, result) + (* Temporarily allow Arrays, to split up error diff. *) + | (DefT (_, _, ArrT _), GetDictValuesT (reason, result)) + | (DefT (_, _, ObjT _), GetDictValuesT (reason, result)) + | (DefT (_, _, InstanceT _), GetDictValuesT (reason, result)) -> + rec_flow cx trace (MixedT.why reason (bogus_trust ()), result) + (* Any will always be ok *) + | (AnyT (_, src), GetDictValuesT (reason, result)) -> + rec_flow cx trace (AnyT.why src reason, result) (*******************************************) (* Refinement based on function predicates *) (*******************************************) @@ -6164,6 +6186,7 @@ struct | GetProtoT _ | GetStaticsT _ | GetValuesT _ + | GetDictValuesT _ | GuardT _ | FilterOptionalT _ | FilterMaybeT _ diff --git a/src/typing/flow_js_utils.ml b/src/typing/flow_js_utils.ml index afcc7076705..ec9bf579e89 100644 --- a/src/typing/flow_js_utils.ml +++ b/src/typing/flow_js_utils.ml @@ -173,6 +173,7 @@ let object_like_op = function | GetKeysT _ | HasOwnPropT _ | GetValuesT _ + | GetDictValuesT _ | ObjAssignToT _ | ObjAssignFromT _ | ObjRestT _ @@ -411,6 +412,7 @@ let error_message_kind_of_upper = function Error_message.IncompatibleHasOwnPropT (aloc_of_reason r, Some name) | HasOwnPropT (_, r, _) -> Error_message.IncompatibleHasOwnPropT (aloc_of_reason r, None) | GetValuesT _ -> Error_message.IncompatibleGetValuesT + | GetDictValuesT _ -> Error_message.IncompatibleGetValuesT | UnaryArithT _ -> Error_message.IncompatibleUnaryArithT | MapTypeT (_, _, (ObjectMap _ | ObjectMapi _ | ObjectMapConst _ | ObjectKeyMirror), _) -> Error_message.IncompatibleMapTypeTObject diff --git a/src/typing/implicit_instantiation.ml b/src/typing/implicit_instantiation.ml index df1c7d7c34f..771daa20655 100644 --- a/src/typing/implicit_instantiation.ml +++ b/src/typing/implicit_instantiation.ml @@ -257,6 +257,7 @@ struct | OptionalIndexedAccessT _ | GetKeysT _ | GetValuesT _ + | GetDictValuesT _ (* Import-export related upper bounds won't appear during implicit instantiation. *) | CJSRequireT _ | ImportModuleNsT _ diff --git a/src/typing/statement.ml b/src/typing/statement.ml index cae595f0c98..b6e307f42ff 100644 --- a/src/typing/statement.ml +++ b/src/typing/statement.ml @@ -5785,6 +5785,26 @@ module Make } ) in + let get_keys ~arr_reason obj_t = + Tvar.mk_where cx arr_reason (fun tvar -> + let keys_reason = + update_desc_reason + (fun desc -> RCustom (spf "element of %s" (string_of_desc desc))) + reason + in + Flow.flow cx (obj_t, GetKeysT (keys_reason, UseT (use_op, tvar))) + ) + in + let get_values ~arr_reason obj_t = + Tvar.mk_where cx arr_reason (fun tvar -> + let values_reason = + update_desc_reason + (fun desc -> RCustom (spf "element of %s" (string_of_desc desc))) + reason + in + Flow.flow cx (obj_t, GetDictValuesT (values_reason, UseT (use_op, tvar))) + ) + in match (m, targs, args) with | ("create", None, (args_loc, { ArgList.arguments = [Expression e]; comments })) -> let (((_, e_t), _) as e_ast) = expression cx e in @@ -5871,23 +5891,28 @@ module Make ) -> let arr_reason = mk_reason RArrayType loc in let (((_, o), _) as e_ast) = expression cx e in - ( DefT - ( arr_reason, - bogus_trust (), - ArrT - (ArrayAT - ( Tvar.mk_where cx arr_reason (fun tvar -> - let keys_reason = - update_desc_reason - (fun desc -> RCustom (spf "element of %s" (string_of_desc desc))) - reason - in - Flow.flow cx (o, GetKeysT (keys_reason, UseT (use_op, tvar))) - ), - None - ) - ) - ), + let keys_t = get_keys ~arr_reason o in + ( DefT (arr_reason, bogus_trust (), ArrT (ArrayAT (keys_t, None))), + None, + (args_loc, { ArgList.arguments = [Expression e_ast]; comments }) + ) + | ("values", None, (args_loc, { ArgList.arguments = [Expression e]; comments })) -> + let arr_reason = mk_reason RArrayType loc in + let (((_, o), _) as e_ast) = expression cx e in + ( DefT (arr_reason, bogus_trust (), ArrT (ArrayAT (get_values ~arr_reason o, None))), + None, + (args_loc, { ArgList.arguments = [Expression e_ast]; comments }) + ) + | ("entries", None, (args_loc, { ArgList.arguments = [Expression e]; comments })) -> + let arr_reason = mk_reason RArrayType loc in + let (((_, o), _) as e_ast) = expression cx e in + let keys_t = get_keys ~arr_reason o in + let values_t = get_values ~arr_reason o in + let elem_t = UnionT (mk_reason RTupleElement loc, UnionRep.make keys_t values_t []) in + let entry_t = + DefT (mk_reason RTupleType loc, bogus_trust (), ArrT (TupleAT (elem_t, [keys_t; values_t]))) + in + ( DefT (arr_reason, bogus_trust (), ArrT (ArrayAT (entry_t, None))), None, (args_loc, { ArgList.arguments = [Expression e_ast]; comments }) ) diff --git a/src/typing/type.ml b/src/typing/type.ml index 6752cfef039..c8a304ff216 100644 --- a/src/typing/type.ml +++ b/src/typing/type.ml @@ -665,6 +665,8 @@ module rec TypeTerm : sig | HasOwnPropT of use_op * reason * t (* The incoming string that we want to check against *) (* Values *) | GetValuesT of reason * t + (* Values of a dictionary, `mixed` otherwise. *) + | GetDictValuesT of reason * use_t (* Element access *) | ElemT of use_op * reason * t * elem_action (* exact ops *) @@ -3686,6 +3688,7 @@ let string_of_use_ctor = function | GetElemT _ -> "GetElemT" | GetKeysT _ -> "GetKeysT" | GetValuesT _ -> "GetValuesT" + | GetDictValuesT _ -> "GetDictValuesT" | GetPropT _ -> "GetPropT" | GetPrivatePropT _ -> "GetPrivatePropT" | GetProtoT _ -> "GetProtoT" diff --git a/src/typing/typeUtil.ml b/src/typing/typeUtil.ml index 0cad24b0d2f..c29c01ec0f5 100644 --- a/src/typing/typeUtil.ml +++ b/src/typing/typeUtil.ml @@ -90,6 +90,7 @@ and reason_of_use_t = function | GetElemT (_, reason, _, _, _) -> reason | GetKeysT (reason, _) -> reason | GetValuesT (reason, _) -> reason + | GetDictValuesT (reason, _) -> reason | GetPropT (_, reason, _, _, _) -> reason | GetPrivatePropT (_, reason, _, _, _, _) -> reason | GetProtoT (reason, _) -> reason @@ -266,6 +267,7 @@ and mod_reason_of_use_t f = function | GetElemT (use_op, reason, annot, it, et) -> GetElemT (use_op, f reason, annot, it, et) | GetKeysT (reason, t) -> GetKeysT (f reason, t) | GetValuesT (reason, t) -> GetValuesT (f reason, t) + | GetDictValuesT (reason, t) -> GetDictValuesT (f reason, t) | GetPropT (use_op, reason, id, n, t) -> GetPropT (use_op, f reason, id, n, t) | GetPrivatePropT (use_op, reason, name, bindings, static, t) -> GetPrivatePropT (use_op, f reason, name, bindings, static, t) @@ -418,6 +420,7 @@ let rec util_use_op_of_use_t : | ArrRestT (op, r, i, t) -> util op (fun op -> ArrRestT (op, r, i, t)) | HasOwnPropT (op, r, t) -> util op (fun op -> HasOwnPropT (op, r, t)) | GetKeysT (r, u2) -> nested_util u2 (fun u2 -> GetKeysT (r, u2)) + | GetDictValuesT (r, u2) -> nested_util u2 (fun u2 -> GetDictValuesT (r, u2)) | ElemT (op, r, t, a) -> util op (fun op -> ElemT (op, r, t, a)) | ObjKitT (op, r, x, y, t) -> util op (fun op -> ObjKitT (op, r, x, y, t)) | ReactKitT (op, r, t) -> util op (fun op -> ReactKitT (op, r, t)) diff --git a/tests/object_api/object_api.exp b/tests/object_api/object_api.exp index f7f159cd404..6c9a31ffc4b 100644 --- a/tests/object_api/object_api.exp +++ b/tests/object_api/object_api.exp @@ -29,64 +29,204 @@ References: ^ [2] -Error ------------------------------------------------------------------------------------------ object_entries.js:13:16 +Error ------------------------------------------------------------------------------------------- object_entries.js:27:2 -Cannot call method `entries` with `undefined` bound to `object` because undefined [1] is incompatible with interface -type [2]. [incompatible-call] +Cannot cast `Object.entries(...)` to array type because number [1] is incompatible with empty [2] in array element. +[incompatible-cast] - object_entries.js:13:16 - 13| Object.entries(undefined); // ERROR - ^^^^^^^^^ [1] + object_entries.js:27:2 + 27| (Object.entries(dict): Array<[string, empty]>); // ERROR + ^^^^^^^^^^^^^^^^^^^^ References: - /core.js:130:28 - 130| static entries(object: interface {}): Array<[string, mixed]>; - ^^^^^^^^^^^^ [2] + object_entries.js:1:30 + 1| declare var dict: {[string]: number}; + ^^^^^^ [1] + object_entries.js:27:39 + 27| (Object.entries(dict): Array<[string, empty]>); // ERROR + ^^^^^ [2] -Error ------------------------------------------------------------------------------------------ object_entries.js:14:16 +Error ------------------------------------------------------------------------------------------- object_entries.js:28:2 -Cannot call method `entries` with `null` bound to `object` because null [1] is incompatible with interface type [2]. -[incompatible-call] +Cannot cast `Object.entries(...)` to array type because mixed [1] is incompatible with empty [2] in array element. +[incompatible-cast] - object_entries.js:14:16 - 14| Object.entries(null); // ERROR - ^^^^ [1] + object_entries.js:28:2 + 28| (Object.entries(iface): Array<[string, empty]>); // ERROR + ^^^^^^^^^^^^^^^^^^^^^ [1] References: - /core.js:130:28 - 130| static entries(object: interface {}): Array<[string, mixed]>; - ^^^^^^^^^^^^ [2] + object_entries.js:28:40 + 28| (Object.entries(iface): Array<[string, empty]>); // ERROR + ^^^^^ [2] -Error ------------------------------------------------------------------------------------------ object_entries.js:15:16 +Error ------------------------------------------------------------------------------------------- object_entries.js:29:2 -Cannot call method `entries` with `1` bound to `object` because number [1] is incompatible with interface type [2]. -[incompatible-call] +Cannot cast `Object.entries(...)` to array type because mixed [1] is incompatible with empty [2] in array element. +[incompatible-cast] - object_entries.js:15:16 - 15| Object.entries(1); // ERROR - ^ [1] + object_entries.js:29:2 + 29| (Object.entries(dictWithProps): Array<[string, empty]>); // ERROR + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] References: - /core.js:130:28 - 130| static entries(object: interface {}): Array<[string, mixed]>; - ^^^^^^^^^^^^ [2] + object_entries.js:29:48 + 29| (Object.entries(dictWithProps): Array<[string, empty]>); // ERROR + ^^^^^ [2] -Error ------------------------------------------------------------------------------------------ object_entries.js:16:16 +Error ------------------------------------------------------------------------------------------- object_entries.js:30:2 -Cannot call method `entries` with `true` bound to `object` because boolean [1] is incompatible with interface type [2]. -[incompatible-call] +Cannot cast `Object.entries(...)` to array type because number [1] is incompatible with empty [2] in array element. +[incompatible-cast] - object_entries.js:16:16 - 16| Object.entries(true); // ERROR - ^^^^ [1] + object_entries.js:30:2 + 30| (Object.entries(dictUnion): Array<[string, empty]>); // ERROR + ^^^^^^^^^^^^^^^^^^^^^^^^^ + +References: + object_entries.js:7:35 + 7| declare var dictUnion: {[string]: number} | {[string]: boolean}; + ^^^^^^ [1] + object_entries.js:30:44 + 30| (Object.entries(dictUnion): Array<[string, empty]>); // ERROR + ^^^^^ [2] + + +Error ------------------------------------------------------------------------------------------- object_entries.js:30:2 + +Cannot cast `Object.entries(...)` to array type because boolean [1] is incompatible with empty [2] in array element. +[incompatible-cast] + + object_entries.js:30:2 + 30| (Object.entries(dictUnion): Array<[string, empty]>); // ERROR + ^^^^^^^^^^^^^^^^^^^^^^^^^ + +References: + object_entries.js:7:56 + 7| declare var dictUnion: {[string]: number} | {[string]: boolean}; + ^^^^^^^ [1] + object_entries.js:30:44 + 30| (Object.entries(dictUnion): Array<[string, empty]>); // ERROR + ^^^^^ [2] + + +Error ------------------------------------------------------------------------------------------- object_entries.js:31:2 + +Cannot cast `Object.entries(...)` to array type because mixed [1] is incompatible with empty [2] in array element. +[incompatible-cast] + + object_entries.js:31:2 + 31| (Object.entries(writeOnlyDict): Array<[string, empty]>); // ERROR + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + +References: + object_entries.js:31:48 + 31| (Object.entries(writeOnlyDict): Array<[string, empty]>); // ERROR + ^^^^^ [2] + + +Error ------------------------------------------------------------------------------------------- object_entries.js:32:2 + +Cannot cast `Object.entries(...)` to array type because mixed [1] is incompatible with empty [2] in array element. +[incompatible-cast] + + object_entries.js:32:2 + 32| (Object.entries(obj): Array<['a' | 'b', empty]>); // ERROR + ^^^^^^^^^^^^^^^^^^^ [1] + +References: + object_entries.js:32:41 + 32| (Object.entries(obj): Array<['a' | 'b', empty]>); // ERROR + ^^^^^ [2] + + +Error ------------------------------------------------------------------------------------------- object_entries.js:33:2 + +Cannot cast `Object.entries(...)` to array type because mixed [1] is incompatible with empty [2] in array element. +[incompatible-cast] + + object_entries.js:33:2 + 33| (Object.entries(instance): Array<['a' | 'b', empty]>); // ERROR + ^^^^^^^^^^^^^^^^^^^^^^^^ [1] + +References: + object_entries.js:33:46 + 33| (Object.entries(instance): Array<['a' | 'b', empty]>); // ERROR + ^^^^^ [2] + + +Error ------------------------------------------------------------------------------------------- object_entries.js:34:2 + +Cannot cast `Object.entries(...)` to array type because tuple type [1] is incompatible with empty [2] in array element. +[incompatible-cast] + + object_entries.js:34:2 + 34| (Object.entries(dict): Array); // ERROR + ^^^^^^^^^^^^^^^^^^^^ [1] + +References: + object_entries.js:34:30 + 34| (Object.entries(dict): Array); // ERROR + ^^^^^ [2] + + +Error ------------------------------------------------------------------------------------------- object_entries.js:37:8 + +Cannot call method `entries` because undefined [1] is not an object. [not-an-object] + + object_entries.js:37:8 + 37| Object.entries(undefined); // ERROR + ^^^^^^^ + +References: + object_entries.js:37:16 + 37| Object.entries(undefined); // ERROR + ^^^^^^^^^ [1] + + +Error ------------------------------------------------------------------------------------------- object_entries.js:38:8 + +Cannot call method `entries` because null [1] is not an object. [not-an-object] + + object_entries.js:38:8 + 38| Object.entries(null); // ERROR + ^^^^^^^ References: - /core.js:130:28 - 130| static entries(object: interface {}): Array<[string, mixed]>; - ^^^^^^^^^^^^ [2] + object_entries.js:38:16 + 38| Object.entries(null); // ERROR + ^^^^ [1] + + +Error ------------------------------------------------------------------------------------------- object_entries.js:39:8 + +Cannot call method `entries` because number [1] is not an object. [not-an-object] + + object_entries.js:39:8 + 39| Object.entries(1); // ERROR + ^^^^^^^ + +References: + object_entries.js:39:16 + 39| Object.entries(1); // ERROR + ^ [1] + + +Error ------------------------------------------------------------------------------------------- object_entries.js:40:8 + +Cannot call method `entries` because boolean [1] is not an object. [not-an-object] + + object_entries.js:40:8 + 40| Object.entries(true); // ERROR + ^^^^^^^ + +References: + object_entries.js:40:16 + 40| Object.entries(true); // ERROR + ^^^^ [1] Error ----------------------------------------------------------------------------------------------- object_keys.js:5:2 @@ -955,64 +1095,189 @@ References: ^^^^^^^^^^^^^^^^^^^^^^^^ [2] -Error ------------------------------------------------------------------------------------------- object_values.js:13:15 +Error -------------------------------------------------------------------------------------------- object_values.js:27:2 -Cannot call method `values` with `undefined` bound to `object` because undefined [1] is incompatible with interface -type [2]. [incompatible-call] +Cannot cast `Object.values(...)` to array type because number [1] is incompatible with empty [2] in array element. +[incompatible-cast] - object_values.js:13:15 - 13| Object.values(undefined); // ERROR - ^^^^^^^^^ [1] + object_values.js:27:2 + 27| (Object.values(dict): Array); // ERROR + ^^^^^^^^^^^^^^^^^^^ References: - /core.js:221:27 - 221| static values(object: interface {}): Array; - ^^^^^^^^^^^^ [2] + object_values.js:1:30 + 1| declare var dict: {[string]: number}; + ^^^^^^ [1] + object_values.js:27:29 + 27| (Object.values(dict): Array); // ERROR + ^^^^^ [2] -Error ------------------------------------------------------------------------------------------- object_values.js:14:15 +Error -------------------------------------------------------------------------------------------- object_values.js:28:2 -Cannot call method `values` with `null` bound to `object` because null [1] is incompatible with interface type [2]. -[incompatible-call] +Cannot cast `Object.values(...)` to array type because mixed [1] is incompatible with empty [2] in array element. +[incompatible-cast] - object_values.js:14:15 - 14| Object.values(null); // ERROR - ^^^^ [1] + object_values.js:28:2 + 28| (Object.values(iface): Array); // ERROR + ^^^^^^^^^^^^^^^^^^^^ [1] References: - /core.js:221:27 - 221| static values(object: interface {}): Array; - ^^^^^^^^^^^^ [2] + object_values.js:28:30 + 28| (Object.values(iface): Array); // ERROR + ^^^^^ [2] -Error ------------------------------------------------------------------------------------------- object_values.js:15:15 +Error -------------------------------------------------------------------------------------------- object_values.js:29:2 -Cannot call method `values` with `1` bound to `object` because number [1] is incompatible with interface type [2]. -[incompatible-call] +Cannot cast `Object.values(...)` to array type because mixed [1] is incompatible with empty [2] in array element. +[incompatible-cast] - object_values.js:15:15 - 15| Object.values(1); // ERROR - ^ [1] + object_values.js:29:2 + 29| (Object.values(dictWithProps): Array); // ERROR + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] References: - /core.js:221:27 - 221| static values(object: interface {}): Array; - ^^^^^^^^^^^^ [2] + object_values.js:29:38 + 29| (Object.values(dictWithProps): Array); // ERROR + ^^^^^ [2] -Error ------------------------------------------------------------------------------------------- object_values.js:16:15 +Error -------------------------------------------------------------------------------------------- object_values.js:30:2 -Cannot call method `values` with `true` bound to `object` because boolean [1] is incompatible with interface type [2]. -[incompatible-call] +Cannot cast `Object.values(...)` to array type because number [1] is incompatible with empty [2] in array element. +[incompatible-cast] - object_values.js:16:15 - 16| Object.values(true); // ERROR - ^^^^ [1] + object_values.js:30:2 + 30| (Object.values(dictUnion): Array); // ERROR + ^^^^^^^^^^^^^^^^^^^^^^^^ + +References: + object_values.js:7:35 + 7| declare var dictUnion: {[string]: number} | {[string]: boolean}; + ^^^^^^ [1] + object_values.js:30:34 + 30| (Object.values(dictUnion): Array); // ERROR + ^^^^^ [2] + + +Error -------------------------------------------------------------------------------------------- object_values.js:30:2 + +Cannot cast `Object.values(...)` to array type because boolean [1] is incompatible with empty [2] in array element. +[incompatible-cast] + + object_values.js:30:2 + 30| (Object.values(dictUnion): Array); // ERROR + ^^^^^^^^^^^^^^^^^^^^^^^^ + +References: + object_values.js:7:56 + 7| declare var dictUnion: {[string]: number} | {[string]: boolean}; + ^^^^^^^ [1] + object_values.js:30:34 + 30| (Object.values(dictUnion): Array); // ERROR + ^^^^^ [2] + + +Error -------------------------------------------------------------------------------------------- object_values.js:31:2 + +Cannot cast `Object.values(...)` to array type because mixed [1] is incompatible with empty [2] in array element. +[incompatible-cast] + + object_values.js:31:2 + 31| (Object.values(writeOnlyDict): Array); // ERROR + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] + +References: + object_values.js:31:38 + 31| (Object.values(writeOnlyDict): Array); // ERROR + ^^^^^ [2] + + +Error -------------------------------------------------------------------------------------------- object_values.js:32:2 + +Cannot cast `Object.values(...)` to array type because mixed [1] is incompatible with empty [2] in array element. +[incompatible-cast] + + object_values.js:32:2 + 32| (Object.values(obj): Array); // ERROR + ^^^^^^^^^^^^^^^^^^ [1] + +References: + object_values.js:32:28 + 32| (Object.values(obj): Array); // ERROR + ^^^^^ [2] + + +Error -------------------------------------------------------------------------------------------- object_values.js:33:2 + +Cannot cast `Object.values(...)` to array type because mixed [1] is incompatible with empty [2] in array element. +[incompatible-cast] + + object_values.js:33:2 + 33| (Object.values(instance): Array); // ERROR + ^^^^^^^^^^^^^^^^^^^^^^^ [1] + +References: + object_values.js:33:33 + 33| (Object.values(instance): Array); // ERROR + ^^^^^ [2] + + +Error -------------------------------------------------------------------------------------------- object_values.js:36:8 + +Cannot call method `values` because undefined [1] is not an object. [not-an-object] + + object_values.js:36:8 + 36| Object.values(undefined); // ERROR + ^^^^^^ + +References: + object_values.js:36:15 + 36| Object.values(undefined); // ERROR + ^^^^^^^^^ [1] + + +Error -------------------------------------------------------------------------------------------- object_values.js:37:8 + +Cannot call method `values` because null [1] is not an object. [not-an-object] + + object_values.js:37:8 + 37| Object.values(null); // ERROR + ^^^^^^ + +References: + object_values.js:37:15 + 37| Object.values(null); // ERROR + ^^^^ [1] + + +Error -------------------------------------------------------------------------------------------- object_values.js:38:8 + +Cannot call method `values` because number [1] is not an object. [not-an-object] + + object_values.js:38:8 + 38| Object.values(1); // ERROR + ^^^^^^ + +References: + object_values.js:38:15 + 38| Object.values(1); // ERROR + ^ [1] + + +Error -------------------------------------------------------------------------------------------- object_values.js:39:8 + +Cannot call method `values` because boolean [1] is not an object. [not-an-object] + + object_values.js:39:8 + 39| Object.values(true); // ERROR + ^^^^^^ References: - /core.js:221:27 - 221| static values(object: interface {}): Array; - ^^^^^^^^^^^^ [2] + object_values.js:39:15 + 39| Object.values(true); // ERROR + ^^^^ [1] Error ----------------------------------------------------------------------------------------------------- proto.js:3:2 @@ -1093,4 +1358,4 @@ References: -Found 70 errors +Found 87 errors diff --git a/tests/object_api/object_entries.js b/tests/object_api/object_entries.js index 548e9750826..5839dc1087e 100644 --- a/tests/object_api/object_entries.js +++ b/tests/object_api/object_entries.js @@ -1,13 +1,37 @@ -Object.entries({a: 1}); // OK +declare var dict: {[string]: number}; -class A { +declare var dictWithProps: {[string]: number, a: boolean}; + +declare var writeOnlyDict: {-[string]: number}; + +declare var dictUnion: {[string]: number} | {[string]: boolean}; + +declare var obj: {a: 1, b: 2}; + +declare class C { a: number; - constructor(a: number) { - this.a = a; - } + b: string; } -const a = new A(1); -Object.entries(a); // OK +declare var instance: C; + +declare var iface: interface {[string]: number}; + +(Object.entries(dict): Array<[string, number]>); // OK +(Object.entries(iface): Array<[string, mixed]>); // OK +(Object.entries(dictWithProps): Array<[string, mixed]>); // OK +(Object.entries(dictUnion): Array<[string, number | boolean]>); // OK +(Object.entries(writeOnlyDict): Array<[string, mixed]>); // OK +(Object.entries(obj): Array<['a' | 'b', mixed]>); // OK +(Object.entries(instance): Array<['a' | 'b', mixed]>); // OK + +(Object.entries(dict): Array<[string, empty]>); // ERROR +(Object.entries(iface): Array<[string, empty]>); // ERROR +(Object.entries(dictWithProps): Array<[string, empty]>); // ERROR +(Object.entries(dictUnion): Array<[string, empty]>); // ERROR +(Object.entries(writeOnlyDict): Array<[string, empty]>); // ERROR +(Object.entries(obj): Array<['a' | 'b', empty]>); // ERROR +(Object.entries(instance): Array<['a' | 'b', empty]>); // ERROR +(Object.entries(dict): Array); // ERROR // Invalid inputs Object.entries(undefined); // ERROR diff --git a/tests/object_api/object_values.js b/tests/object_api/object_values.js index 8b3ede051c1..10eac5bdcf4 100644 --- a/tests/object_api/object_values.js +++ b/tests/object_api/object_values.js @@ -1,13 +1,36 @@ -Object.entries({a: 1}); // OK +declare var dict: {[string]: number}; -class A { +declare var dictWithProps: {[string]: number, a: boolean}; + +declare var writeOnlyDict: {-[string]: number}; + +declare var dictUnion: {[string]: number} | {[string]: boolean}; + +declare var obj: {a: 1, b: 2}; + +declare class C { a: number; - constructor(a: number) { - this.a = a; - } + b: string; } -const a = new A(1); -Object.entries(a); // OK +declare var instance: C; + +declare var iface: interface {[string]: number}; + +(Object.values(dict): Array); // OK +(Object.values(iface): Array); // OK +(Object.values(dictWithProps): Array); // OK +(Object.values(dictUnion): Array); // OK +(Object.values(writeOnlyDict): Array); // OK +(Object.values(obj): Array); // OK +(Object.values(instance): Array); // OK + +(Object.values(dict): Array); // ERROR +(Object.values(iface): Array); // ERROR +(Object.values(dictWithProps): Array); // ERROR +(Object.values(dictUnion): Array); // ERROR +(Object.values(writeOnlyDict): Array); // ERROR +(Object.values(obj): Array); // ERROR +(Object.values(instance): Array); // ERROR // Invalid inputs Object.values(undefined); // ERROR