diff --git a/src/typing/errors/error_message.ml b/src/typing/errors/error_message.ml index cf40a19beec..89c29c49f4e 100644 --- a/src/typing/errors/error_message.ml +++ b/src/typing/errors/error_message.ml @@ -788,6 +788,7 @@ let map_loc_of_explanation (f : 'a -> 'b) = { name; declaration = f declaration; providers = Base.List.map ~f providers } | ExplanationConcreteEnumCasting { representation_type; casting_syntax } -> ExplanationConcreteEnumCasting { representation_type; casting_syntax } + | ExplanationFunctionsWithStaticsToObject -> ExplanationFunctionsWithStaticsToObject | ExplanationMultiplatform -> ExplanationMultiplatform | ExplanationNonCallableObjectToFunction -> ExplanationNonCallableObjectToFunction | ExplanationPropertyInvariantTyping -> ExplanationPropertyInvariantTyping diff --git a/src/typing/errors/flow_intermediate_error.ml b/src/typing/errors/flow_intermediate_error.ml index 4e239727e9f..d96175c2e03 100644 --- a/src/typing/errors/flow_intermediate_error.ml +++ b/src/typing/errors/flow_intermediate_error.ml @@ -1091,6 +1091,8 @@ let to_printable_error : text "https://flow.org/en/docs/faq/#why-cant-i-pass-an-arraystring-to-a-function-that-takes-an-arraystring-number"; ] + | ExplanationFunctionsWithStaticsToObject -> + [text "Functions without statics are not compatible with objects"] | ExplanationMultiplatform -> [ text "Read the docs on Flow's multi-platform support for more information: "; diff --git a/src/typing/errors/flow_intermediate_error_types.ml b/src/typing/errors/flow_intermediate_error_types.ml index 2dc13907ec8..bddd8bb76e2 100644 --- a/src/typing/errors/flow_intermediate_error_types.ml +++ b/src/typing/errors/flow_intermediate_error_types.ml @@ -179,6 +179,7 @@ type 'loc explanation = representation_type: string; casting_syntax: Options.CastingSyntax.t; } + | ExplanationFunctionsWithStaticsToObject | ExplanationMultiplatform | ExplanationNonCallableObjectToFunction | ExplanationPropertyInvariantTyping diff --git a/src/typing/flow_js_utils.ml b/src/typing/flow_js_utils.ml index 8c3e6518b1e..f28999cdeb9 100644 --- a/src/typing/flow_js_utils.ml +++ b/src/typing/flow_js_utils.ml @@ -807,19 +807,35 @@ let quick_error_fun_as_obj cx ~use_op reason statics reason_o props = not (optional || is_function_prototype x || NameUtils.Map.mem x statics_own_props)) props in - NameUtils.Map.iter - (fun x _ -> - let use_op = - Frame (PropertyCompatibility { prop = Some x; lower = reason; upper = reason_o }, use_op) - in - let reason_prop = update_desc_reason (fun desc -> RPropertyOf (x, desc)) reason_o in - let err = - Error_message.EPropNotFound - { prop_name = Some x; reason_prop; reason_obj = reason; use_op; suggestion = None } - in - add_output cx err) - props_not_found; - not (NameUtils.Map.is_empty props_not_found) + if NameUtils.Map.is_empty props_not_found then + false + else if NameUtils.Map.is_empty statics_own_props && not (NameUtils.Map.is_empty props) then ( + let error_message = + Error_message.EIncompatibleWithUseOp + { + reason_lower = reason; + reason_upper = reason_o; + use_op; + explanation = Some Flow_intermediate_error_types.ExplanationFunctionsWithStaticsToObject; + } + in + add_output cx error_message; + true + ) else ( + NameUtils.Map.iter + (fun x _ -> + let use_op = + Frame (PropertyCompatibility { prop = Some x; lower = reason; upper = reason_o }, use_op) + in + let reason_prop = update_desc_reason (fun desc -> RPropertyOf (x, desc)) reason_o in + let err = + Error_message.EPropNotFound + { prop_name = Some x; reason_prop; reason_obj = reason; use_op; suggestion = None } + in + add_output cx err) + props_not_found; + true + ) | None -> false (** Instantiation *) diff --git a/tests/call_properties/call_properties.exp b/tests/call_properties/call_properties.exp index 310785bdb31..b1cf2e2f99a 100644 --- a/tests/call_properties/call_properties.exp +++ b/tests/call_properties/call_properties.exp @@ -227,8 +227,8 @@ References: Error -------------------------------------------------------------------------------------------------------- E.js:2:32 -Cannot assign function to `a` because property `someProp` is missing in function [1] but exists in object type [2]. -[prop-missing] +Cannot assign function to `a` because function [1] is incompatible with object type [2]. Functions without statics are +not compatible with objects. [incompatible-type] E.js:2:32 2| var a : { someProp: number } = function () {}; diff --git a/tests/component_syntax/component_syntax.exp b/tests/component_syntax/component_syntax.exp index c751a89d906..a1eb50a98fd 100644 --- a/tests/component_syntax/component_syntax.exp +++ b/tests/component_syntax/component_syntax.exp @@ -2729,7 +2729,7 @@ Error -------------------------------------------------------------------------- Cannot create `meta` element because in property `ref`: [incompatible-type] - Either `HTMLAnchorElement` [1] is incompatible with `HTMLMetaElement` [2] in the first parameter. - - Or property `current` is missing in function type [3] but exists in object type [4]. + - Or function type [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. propsof.js:28:22 28| let b = ; // error @@ -2844,7 +2844,7 @@ Error -------------------------------------------------------------------------- Cannot declare ref because: [incompatible-type] - Either component Reffed [1] is incompatible with null [2] in the first parameter. - - Or property `current` is missing in function type [3] but exists in object type [4]. + - Or function type [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. The `ref` parameter must be a subtype of `React.RefSetter`. @@ -3142,7 +3142,8 @@ References: Error ----------------------------------------------------------------------------------------------------- refs.js:17:2 Cannot cast `Baz` to component because: [incompatible-cast] - - Either property `current` is missing in function type [1] but exists in object type [2]. + - Either function type [1] is incompatible with object type [2]. Functions without statics are not compatible with + objects. - Or component Reffed [3] is incompatible with string [4] in the first parameter. refs.js:17:2 @@ -3195,7 +3196,7 @@ Error -------------------------------------------------------------------------- Cannot create `MyNestedInput` element because in property `ref`: [incompatible-type] - Either `HTMLElement` [1] is incompatible with nullable `HTMLInputElement` [2] in the first parameter. - Or `HTMLElement` [1] is incompatible with `HTMLInputElement` [3] in the first parameter. - - Or property `current` is missing in function type [4] but exists in object type [5]. + - Or function type [4] is incompatible with object type [5]. Functions without statics are not compatible with objects. refs.js:64:53 64| @@ -3252,7 +3253,7 @@ Error -------------------------------------------------------------------------- Cannot create `Foo` element because in property `ref`: [incompatible-type] - Either number [1] is incompatible with boolean [2] in property `bar` of the first parameter. - - Or property `current` is missing in function type [3] but exists in object type [4]. + - Or function type [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. refs.js:92:13 92| ; // error @@ -3321,7 +3322,7 @@ References: Error --------------------------------------------------------------------------------------------------- refs.js:108:23 Cannot create `GenericRef2` element because in property `ref`: [incompatible-type] - - Either property `current` is missing in function [1] but exists in object type [2]. + - Either function [1] is incompatible with object type [2]. Functions without statics are not compatible with objects. - Or array type [3] is incompatible with string [4] in the first parameter. refs.js:108:23 diff --git a/tests/component_type/component_type.exp b/tests/component_type/component_type.exp index 559a260d847..840d8e9534e 100644 --- a/tests/component_type/component_type.exp +++ b/tests/component_type/component_type.exp @@ -35,7 +35,8 @@ References: Error ----------------------------------------------------------------------------------- class_to_component_type.js:7:1 Cannot cast `Foo` to component because: [incompatible-cast] - - Either property `current` is missing in function type [1] but exists in object type [2]. + - Either function type [1] is incompatible with object type [2]. Functions without statics are not compatible with + objects. - Or `Foo` [3] is incompatible with string [4] in the first parameter. class_to_component_type.js:7:1 @@ -191,7 +192,7 @@ Error -------------------------------------------------------------------------- Cannot cast `ComponentNarrower` to component because: [incompatible-cast] - Either `ComponentNarrower` [1] is incompatible with `Component` [2] in the first parameter. - - Or property `current` is missing in function type [3] but exists in object type [4]. + - Or function type [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. classes_lower.js:19:1 19| ComponentNarrower as component(ref: React.RefSetter, ...any); // Error instance type is wrong @@ -241,7 +242,7 @@ Error -------------------------------------------------------------------------- Cannot cast `Component` to component because: [incompatible-cast] - Either `Component` [1] is incompatible with `Subclass` [2] in the first parameter. - - Or property `current` is missing in function type [3] but exists in object type [4]. + - Or function type [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. classes_lower.js:25:1 25| Component as component(ref: React.RefSetter, ...any); // Ok, Instance is covariant @@ -618,7 +619,7 @@ Error -------------------------------------------------------------------------- Cannot cast `Component` to component because: [incompatible-cast] - Either undefined [1] is incompatible with null [2] in the first parameter. - - Or property `current` is missing in function type [1] but exists in object type [3]. + - Or function type [1] is incompatible with object type [3]. Functions without statics are not compatible with objects. function_lower.js:12:1 12| Component as component(ref: React.RefSetter, ...Props); // Error @@ -748,7 +749,7 @@ Error -------------------------------------------------------------------------- Cannot cast `Foo` to component because: [incompatible-cast] - Either undefined [1] is incompatible with null [2] in the first parameter. - - Or property `current` is missing in function type [1] but exists in object type [3]. + - Or function type [1] is incompatible with object type [3]. Functions without statics are not compatible with objects. function_to_component_type.js:8:1 8| Foo as component( // error: void ~> string diff --git a/tests/function_statics/function_statics.exp b/tests/function_statics/function_statics.exp index eb9be9f7c78..02d1aaf99e1 100644 --- a/tests/function_statics/function_statics.exp +++ b/tests/function_statics/function_statics.exp @@ -65,8 +65,8 @@ References: Error --------------------------------------------------------------------------------------------------- arrow.js:33:43 -Cannot assign function to `f` because property `a` is missing in function [1] but exists in object type [2]. -[prop-missing] +Cannot assign function to `f` because function [1] is incompatible with object type [2]. Functions without statics are +not compatible with objects. [incompatible-type] arrow.js:33:43 33| const f: {(): number, a: string, ...} = () => 1; // ERROR on assignment @@ -255,8 +255,8 @@ References: Error ------------------------------------------------------------------------------------- function_expression.js:41:43 -Cannot assign function to `f` because property `a` is missing in function [1] but exists in object type [2]. -[prop-missing] +Cannot assign function to `f` because function [1] is incompatible with object type [2]. Functions without statics are +not compatible with objects. [incompatible-type] function_expression.js:41:43 41| const f: {(): number, a: string, ...} = function () { return 1}; // ERROR on assignment @@ -298,8 +298,8 @@ References: Error ---------------------------------------------------------------------------------- used_as_callable_object.js:33:2 -Cannot cast `add` to `InexactCallableObj` because property `bar` is missing in function [1] but exists in -`InexactCallableObj` [2]. [prop-missing] +Cannot cast `add` to `InexactCallableObj` because function [1] is incompatible with `InexactCallableObj` [2]. Functions +without statics are not compatible with objects. [incompatible-cast] used_as_callable_object.js:33:2 33| (add: InexactCallableObj); // error prop 'bar' missing diff --git a/tests/new_react/new_react.exp b/tests/new_react/new_react.exp index d19dd879d7c..8764e03c9a0 100644 --- a/tests/new_react/new_react.exp +++ b/tests/new_react/new_react.exp @@ -42,8 +42,8 @@ References: Error -------------------------------------------------------------------------------------------------- classes.js:23:3 -Cannot extend `React.Component` [1] with `Foo` because property `y_` is missing in function type [2] but exists in -object type [3] in the first parameter of property `setState`. [prop-missing] +Cannot extend `React.Component` [1] with `Foo` because property `y_` is missing in object type [2] but exists in object +type [3] in the first parameter of property `setState`. [prop-missing] classes.js:23:3 23| setState(o: { y_: string }): void { } @@ -53,39 +53,36 @@ References: classes.js:7:19 7| class Foo extends React.Component { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] - /react.js:39:49 - 39| partialState: ?$ReadOnly> | ((State, Props) => ?$ReadOnly>), - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2] + classes.js:7:42 + 7| class Foo extends React.Component { + ^^^^^ [2] classes.js:23:15 23| setState(o: { y_: string }): void { } ^^^^^^^^^^^^^^ [3] -Error -------------------------------------------------------------------------------------------------- classes.js:23:3 +Error ------------------------------------------------------------------------------------------------- classes.js:23:15 -Cannot extend `React.Component` [1] with `Foo` because property `y_` is missing in object type [2] but exists in object -type [3] in the first parameter of property `setState`. [prop-missing] +Cannot extend `React.Component` [1] with `Foo` because object type [2] is incompatible with nullable `$ReadOnly` [3] in +the first parameter of property `setState`. [incompatible-extend] - classes.js:23:3 + classes.js:23:15 23| setState(o: { y_: string }): void { } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + ^^^^^^^^^^^^^^ [2] References: classes.js:7:19 7| class Foo extends React.Component { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] - classes.js:7:42 - 7| class Foo extends React.Component { - ^^^^^ [2] - classes.js:23:15 - 23| setState(o: { y_: string }): void { } - ^^^^^^^^^^^^^^ [3] + /react.js:39:19 + 39| partialState: ?$ReadOnly> | ((State, Props) => ?$ReadOnly>), + ^^^^^^^^^^^^^^^^^^^^^^^^^^ [3] Error ------------------------------------------------------------------------------------------------- classes.js:23:15 -Cannot extend `React.Component` [1] with `Foo` because object type [2] is incompatible with nullable `$ReadOnly` [3] in -the first parameter of property `setState`. [incompatible-extend] +Cannot extend `React.Component` [1] with `Foo` because object type [2] is incompatible with function type [3] in the +first parameter of property `setState`. Functions without statics are not compatible with objects. [incompatible-extend] classes.js:23:15 23| setState(o: { y_: string }): void { } @@ -95,9 +92,9 @@ References: classes.js:7:19 7| class Foo extends React.Component { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1] - /react.js:39:19 + /react.js:39:49 39| partialState: ?$ReadOnly> | ((State, Props) => ?$ReadOnly>), - ^^^^^^^^^^^^^^^^^^^^^^^^^^ [3] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [3] Error ------------------------------------------------------------------------------------------------- classes.js:15:21 diff --git a/tests/react/react.exp b/tests/react/react.exp index bc524761647..206c2544d22 100644 --- a/tests/react/react.exp +++ b/tests/react/react.exp @@ -28,7 +28,7 @@ Error -------------------------------------------------------------------------- Cannot cast `y` to `React.RefSetter` because: [incompatible-cast] - Either boolean [1] is incompatible with number [2] in the first parameter. - Or boolean [1] is incompatible with string [3] in the first parameter. - - Or property `current` is missing in function type [4] but exists in object type [5]. + - Or function type [4] is incompatible with object type [5]. Functions without statics are not compatible with objects. contravariant_refsetter.js:12:2 12| (y: React.RefSetter); // ERROR @@ -1376,7 +1376,7 @@ Error -------------------------------------------------------------------------- Cannot create `Foo` element because in property `ref`: [incompatible-type] - Either number [1] is incompatible with `Foo` [2] in the first parameter. - - Or property `current` is missing in function [3] but exists in object type [4]. + - Or function [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. ref.js:10:11 10| {}} />; // Error: `Foo` is not a `number`. @@ -1456,7 +1456,7 @@ Error -------------------------------------------------------------------------- Cannot create `FooExact` element because in property `ref`: [incompatible-type] - Either number [1] is incompatible with `FooExact` [2] in the first parameter. - - Or property `current` is missing in function [3] but exists in object type [4]. + - Or function [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. ref.js:21:16 21| {}} />; // Error: `FooExact` is not a `number`. @@ -1478,7 +1478,7 @@ Error -------------------------------------------------------------------------- Cannot create `FooExact` element because in property `ref`: [incompatible-type] - Either `FooExact` [1] is incompatible with null [2] in the first parameter. - - Or property `current` is missing in function [3] but exists in object type [4]. + - Or function [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. ref.js:22:16 22| {}} />; // Error: `FooExact` may be null. @@ -1500,7 +1500,7 @@ Error -------------------------------------------------------------------------- Cannot create `FooExact` element because in property `ref`: [incompatible-type] - Either `FooExact` [1] is incompatible with `Bar` [2] in the first parameter. - - Or property `current` is missing in function [3] but exists in object type [4]. + - Or function [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. ref.js:24:16 24| {}} />; // Error: `FooExact` is not `Bar`. @@ -1878,7 +1878,7 @@ Error -------------------------------------------------------------------------- Cannot call `React.useImperativeHandle` with `refSetter` bound to `ref` because: [incompatible-call] - Either property `focus` is missing in object literal [1] but exists in `Interface` [2] in the first parameter. - - Or property `current` is missing in function [3] but exists in object type [4]. + - Or function [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. useImperativeHandle_hook.js:32:29 32| React.useImperativeHandle(refSetter, () => ({})); // Error: inexact object literal is incompatible with exact Interface diff --git a/tests/react_16_3/react_16_3.exp b/tests/react_16_3/react_16_3.exp index 9aa47602dd9..5ddb197dc7e 100644 --- a/tests/react_16_3/react_16_3.exp +++ b/tests/react_16_3/react_16_3.exp @@ -61,7 +61,7 @@ Error -------------------------------------------------------------------------- Cannot create `FancyButton` element because in property `ref`: [incompatible-type] - Either `HTMLButtonElement` [1] is incompatible with `HTMLDivElement` [2] in the first parameter. - - Or property `current` is missing in function [3] but exists in object type [4]. + - Or function [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. forwardRef.js:22:38 22| const _g = x} />; // Incorrect ref type diff --git a/tests/react_16_6/react_16_6.exp b/tests/react_16_6/react_16_6.exp index 5e5b8a5294f..e3786123676 100644 --- a/tests/react_16_6/react_16_6.exp +++ b/tests/react_16_6/react_16_6.exp @@ -80,8 +80,9 @@ References: Error ---------------------------------------------------------------------------------------------------- lazy.js:11:34 -Cannot call `React.lazy` with function bound to `component` because property `default` is missing in function [1] but -exists in object type [2] in type argument `R` [3] of the return value. [prop-missing] +Cannot call `React.lazy` with function bound to `component` because function [1] is incompatible with object type [2] in +type argument `R` [3] of the return value. Functions without statics are not compatible with objects. +[incompatible-call] lazy.js:11:34 11| React.lazy(() => Promise.resolve(FunctionComponent)); // Error property default is missing diff --git a/tests/react_ref_as_prop/react_ref_as_prop.exp b/tests/react_ref_as_prop/react_ref_as_prop.exp index 5360aceabd7..66cbcc028e2 100644 --- a/tests/react_ref_as_prop/react_ref_as_prop.exp +++ b/tests/react_ref_as_prop/react_ref_as_prop.exp @@ -228,7 +228,7 @@ Error -------------------------------------------------------------------------- Cannot create `FnWithOptionalRefProp` element because in property `ref`: [incompatible-type] - Either string [1] is incompatible with `HTMLElement` [2] in the first parameter. - - Or property `current` is missing in function [3] but exists in object type [4]. + - Or function [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. jsx_checking.js:10:39 10| {}} />; // error: string ~> HTMLElement, ref checking still works @@ -250,7 +250,7 @@ Error -------------------------------------------------------------------------- Cannot create `FnWithRequiredRefProp` element because in property `ref`: [incompatible-type] - Either string [1] is incompatible with `HTMLElement` [2] in the first parameter. - - Or property `current` is missing in function [3] but exists in object type [4]. + - Or function [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. jsx_checking.js:12:39 12| {}} />; // error: string ~> HTMLElement, ref checking still works @@ -305,7 +305,7 @@ Error -------------------------------------------------------------------------- Cannot create `CompWithOptionalRefProp` element because in property `ref`: [incompatible-type] - Either string [1] is incompatible with `HTMLElement` [2] in the first parameter. - - Or property `current` is missing in function [3] but exists in object type [4]. + - Or function [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. jsx_checking.js:20:41 20| {}} />; // error: string ~> HTMLElement, ref checking still works @@ -327,7 +327,7 @@ Error -------------------------------------------------------------------------- Cannot create `CompWithRequiredRefProp` element because in property `ref`: [incompatible-type] - Either string [1] is incompatible with `HTMLElement` [2] in the first parameter. - - Or property `current` is missing in function [3] but exists in object type [4]. + - Or function [3] is incompatible with object type [4]. Functions without statics are not compatible with objects. jsx_checking.js:22:41 22| {}} />; // error: string ~> HTMLElement, ref checking still works diff --git a/tests/value_as_type/value_as_type.exp b/tests/value_as_type/value_as_type.exp index aa230a5045a..1ac88fd0933 100644 --- a/tests/value_as_type/value_as_type.exp +++ b/tests/value_as_type/value_as_type.exp @@ -2,7 +2,8 @@ Error -------------------------------------------------------------------------- Cannot create `HocChild` element because in property `ref`: [incompatible-type] - Either `React.Element` [1] is incompatible with mixed [2] in the first parameter. - - Or property `current` is missing in property `_handleChild` [3] but exists in object type [4]. + - Or property `_handleChild` [3] is incompatible with object type [4]. Functions without statics are not compatible + with objects. test1.js:13:45 13| render = (): React.Node => ;