From dd3ec7f63525eaa364a2626f91523a009ded6e60 Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Tue, 7 May 2019 22:26:19 +0500 Subject: [PATCH 01/14] [typing] Add globalThis type --- lib/core.js | 2 ++ src/typing/coverage.ml | 1 + src/typing/debug_js.ml | 4 +++- src/typing/flow_js.ml | 12 +++++++++++- src/typing/members.ml | 1 + src/typing/resolvableTypeJob.ml | 1 + src/typing/sigHash.ml | 2 ++ src/typing/ty_normalizer.ml | 1 + src/typing/type.ml | 7 ++++++- src/typing/type_annotation.ml | 6 ++++++ src/typing/type_mapper.ml | 3 ++- src/typing/type_visitor.ml | 1 + 12 files changed, 37 insertions(+), 4 deletions(-) diff --git a/lib/core.js b/lib/core.js index 590bc1dc798..d224ecc44ba 100644 --- a/lib/core.js +++ b/lib/core.js @@ -908,3 +908,5 @@ declare var console: { warn(...data: Array): void, ... }; + +declare var globalThis: $GlobalThis; \ No newline at end of file diff --git a/src/typing/coverage.ml b/src/typing/coverage.ml index a233fdbbefe..c664af782b7 100644 --- a/src/typing/coverage.ml +++ b/src/typing/coverage.ml @@ -189,6 +189,7 @@ class visitor = object (self) | FunProtoApplyT _ | FunProtoBindT _ | FunProtoCallT _ + | GlobalThisT _ | InternalT _ | KeysT _ | MaybeT _ diff --git a/src/typing/debug_js.ml b/src/typing/debug_js.ml index c4722c28113..32f561f763c 100644 --- a/src/typing/debug_js.ml +++ b/src/typing/debug_js.ml @@ -173,6 +173,7 @@ and _json_of_t_impl json_cx t = Hh_json.( | FunProtoApplyT _ | FunProtoBindT _ | FunProtoCallT _ + | GlobalThisT _ -> [] | DefT (_, _, FunT (static, proto, funtype)) -> [ @@ -1796,7 +1797,8 @@ let rec dump_t_ (depth, tvars) cx t = | FunProtoT _ | FunProtoApplyT _ | FunProtoBindT _ - | FunProtoCallT _ -> p t + | FunProtoCallT _ + | GlobalThisT _ -> p t | DefT (_, trust, PolyT (_, tps, c, id)) -> p ~trust:(Some trust) ~extra:(spf "%s [%s] #%d" (kid c) (String.concat "; " (Core_list.map ~f:(fun tp -> tp.name) (Nel.to_list tps))) diff --git a/src/typing/flow_js.ml b/src/typing/flow_js.ml index 27aa6780f33..a979825a8d4 100644 --- a/src/typing/flow_js.ml +++ b/src/typing/flow_js.ml @@ -6522,6 +6522,14 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace = | FunProtoCallT reason, _ -> rec_flow cx trace (FunProtoT reason, u) + | GlobalThisT _, + SetPropT (_, _, Named (_, name), _, tin, _) -> + set_builtin cx ~trace name tin; + + | GlobalThisT _, _ -> + let t = builtins cx in + rec_flow cx trace (t, u) + | _, LookupT (_, _, _, propref, lookup_action) -> let use_op = use_op_of_lookup_action lookup_action in add_output cx ~trace (Error_message.EIncompatibleProp { @@ -7308,7 +7316,8 @@ and any_propagated_use cx trace use_op any l = | FunProtoCallT _ | FunProtoT _ | ObjProtoT _ - | NullProtoT _ -> + | NullProtoT _ + | GlobalThisT _ -> true (* Handled already in __flow *) @@ -7729,6 +7738,7 @@ and check_polarity cx ?trace polarity = function | FunProtoApplyT _ | FunProtoBindT _ | FunProtoCallT _ + | GlobalThisT _ | EvalT _ | InternalT (ExtendsT _) | InternalT (ChoiceKitT _) diff --git a/src/typing/members.ml b/src/typing/members.ml index efbe9420eb4..a33b2390647 100644 --- a/src/typing/members.ml +++ b/src/typing/members.ml @@ -431,6 +431,7 @@ let rec extract_type cx this_t = match this_t with | FunProtoBindT _ | FunProtoCallT _ | FunProtoT _ + | GlobalThisT _ | KeysT (_, _) | DefT (_, _, MixedT _) | NullProtoT _ diff --git a/src/typing/resolvableTypeJob.ml b/src/typing/resolvableTypeJob.ml index b2381056218..20bb67a7cdf 100644 --- a/src/typing/resolvableTypeJob.ml +++ b/src/typing/resolvableTypeJob.ml @@ -251,6 +251,7 @@ and collect_of_type ?log_unresolved cx acc = function | FunProtoT _ | NullProtoT _ | ObjProtoT _ + | GlobalThisT _ | CustomFunT (_, _) | ExistsT _ diff --git a/src/typing/sigHash.ml b/src/typing/sigHash.ml index a119ac8895a..5a80dba0018 100644 --- a/src/typing/sigHash.ml +++ b/src/typing/sigHash.ml @@ -48,6 +48,7 @@ type hash = | FunProtoApplyH | FunProtoBindH | FunProtoCallH + | GlobalThisH | ObjH | ObjProtoH | MatchingPropH @@ -222,6 +223,7 @@ let hash_of_ctor = Type.(function | FunProtoApplyT _ -> FunProtoApplyH | FunProtoBindT _ -> FunProtoBindH | FunProtoCallT _ -> FunProtoCallH + | GlobalThisT _ -> GlobalThisH | IntersectionT _ -> IntersectionH | KeysT _ -> KeysH | MaybeT _ -> MaybeH diff --git a/src/typing/ty_normalizer.ml b/src/typing/ty_normalizer.ml index cafdaff6951..65f514672a4 100644 --- a/src/typing/ty_normalizer.ml +++ b/src/typing/ty_normalizer.ml @@ -705,6 +705,7 @@ end = struct | ModuleT (reason, _, _) -> module_t env reason t | DefT (_, _, CharSetT _) + | GlobalThisT _ | NullProtoT _ -> terr ~kind:UnsupportedTypeCtor (Some t) diff --git a/src/typing/type.ml b/src/typing/type.ml index f53a38b1ce8..f5703706679 100644 --- a/src/typing/type.ml +++ b/src/typing/type.ml @@ -86,7 +86,7 @@ module rec TypeTerm : sig (* exact *) | ExactT of reason * t - | FunProtoT of reason (* Function.prototype *) + | FunProtoT of reason (* Function.prototype *) | ObjProtoT of reason (* Object.prototype *) (* Signifies the end of the prototype chain. Distinct from NullT when it @@ -97,6 +97,8 @@ module rec TypeTerm : sig | FunProtoBindT of reason (* Function.prototype.bind *) | FunProtoCallT of reason (* Function.prototype.call *) + | GlobalThisT of reason (* globalThis *) + (* generalizations of AnyT *) | AnyWithLowerBoundT of t (* any supertype of t *) | AnyWithUpperBoundT of t (* any subtype of t *) @@ -2143,6 +2145,7 @@ end = struct | FunProtoApplyT reason -> reason | FunProtoBindT reason -> reason | FunProtoCallT reason -> reason + | GlobalThisT reason -> reason | KeysT (reason, _) -> reason | ModuleT (reason, _, _) -> reason | NullProtoT reason -> reason @@ -2307,6 +2310,7 @@ end = struct | FunProtoT (reason) -> FunProtoT (f reason) | FunProtoBindT (reason) -> FunProtoBindT (f reason) | FunProtoCallT (reason) -> FunProtoCallT (f reason) + | GlobalThisT (reason) -> GlobalThisT (f reason) | KeysT (reason, t) -> KeysT (f reason, t) | ModuleT (reason, exports, is_strict) -> ModuleT (f reason, exports, is_strict) | NullProtoT reason -> NullProtoT (f reason) @@ -3118,6 +3122,7 @@ let string_of_ctor = function | FunProtoApplyT _ -> "FunProtoApplyT" | FunProtoBindT _ -> "FunProtoBindT" | FunProtoCallT _ -> "FunProtoCallT" + | GlobalThisT _ -> "GlobalThisT" | KeysT _ -> "KeysT" | ModuleT _ -> "ModuleT" | NullProtoT _ -> "NullProtoT" diff --git a/src/typing/type_annotation.ml b/src/typing/type_annotation.ml index 746fdb97f20..33fa0eb921e 100644 --- a/src/typing/type_annotation.ml +++ b/src/typing/type_annotation.ml @@ -851,6 +851,12 @@ let rec convert cx tparams_map = Ast.Type.(function reconstruct_ast (AnyT.make Annotated reason) None ) + | "$GlobalThis" -> + check_type_arg_arity cx loc t_ast targs 0 (fun () -> + let reason = mk_reason (RCustom "global this") loc in + reconstruct_ast (GlobalThisT reason) None + ) + | "Function$Prototype$Apply" -> check_type_arg_arity cx loc t_ast targs 0 (fun () -> let reason = mk_reason RFunctionType loc in diff --git a/src/typing/type_mapper.ml b/src/typing/type_mapper.ml index 04f7ce8c309..d4b470fdd04 100644 --- a/src/typing/type_mapper.ml +++ b/src/typing/type_mapper.ml @@ -107,7 +107,8 @@ class virtual ['a] t = object(self) | NullProtoT _ | FunProtoApplyT _ | FunProtoBindT _ - | FunProtoCallT _ -> t + | FunProtoCallT _ + | GlobalThisT _ -> t | AnyWithLowerBoundT t' -> let t'' = self#type_ cx map_cx t' in if t'' == t' then t diff --git a/src/typing/type_visitor.ml b/src/typing/type_visitor.ml index fc14976c7e4..7fc5319e6ed 100644 --- a/src/typing/type_visitor.ml +++ b/src/typing/type_visitor.ml @@ -37,6 +37,7 @@ class ['a] t = object(self) | FunProtoCallT _ | ObjProtoT _ | NullProtoT _ + | GlobalThisT _ -> acc | CustomFunT (_, kind) -> self#custom_fun_kind cx acc kind From 703099ceee6aca7d829d4e4044aa3139b5a81ac0 Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Thu, 11 Jul 2019 18:01:25 +0500 Subject: [PATCH 02/14] [common] Add experimental.libs_overrides option --- src/commands/commandUtils.ml | 1 + src/commands/config/flowConfig.ml | 6 ++++++ src/commands/config/flowConfig.mli | 1 + src/common/options.ml | 2 ++ src/flow_dot_js.ml | 1 + 5 files changed, 11 insertions(+) diff --git a/src/commands/commandUtils.ml b/src/commands/commandUtils.ml index 11796e851c0..ff5ac101b0c 100644 --- a/src/commands/commandUtils.ml +++ b/src/commands/commandUtils.ml @@ -1095,6 +1095,7 @@ let make_options ~flowconfig_name ~flowconfig ~lazy_mode ~root (options_flags: O opt_no_saved_state = options_flags.no_saved_state; opt_arch; opt_abstract_locations; + opt_libs_overrides = FlowConfig.libs_overrides flowconfig; opt_include_suppressions = options_flags.include_suppressions; opt_trust_mode = Option.value options_flags.trust_mode ~default:(FlowConfig.trust_mode flowconfig); opt_recursion_limit = FlowConfig.recursion_limit flowconfig; diff --git a/src/commands/config/flowConfig.ml b/src/commands/config/flowConfig.ml index 475cdabd1da..635507fefe1 100644 --- a/src/commands/config/flowConfig.ml +++ b/src/commands/config/flowConfig.ml @@ -43,6 +43,7 @@ module Opts = struct type opt_error = int * error_kind type t = { + libs_overrides: bool; abstract_locations: bool; all: bool; emoji: bool; @@ -134,6 +135,7 @@ module Opts = struct |> SSet.add ".webm" let default_options = { + libs_overrides = false; abstract_locations = false; all = false; emoji = false; @@ -617,6 +619,9 @@ module Opts = struct "experimental.abstract_locations", boolean (fun opts v -> Ok { opts with abstract_locations = v }); + "experimental.libs_overrides", + boolean (fun opts v -> Ok { opts with libs_overrides = v }); + "no_flowlib", boolean (fun opts v -> Ok { opts with no_flowlib = v }); @@ -1014,6 +1019,7 @@ let includes config = config.includes let libs config = config.libs (* options *) +let libs_overrides c = c.options.Opts.libs_overrides let abstract_locations c = c.options.Opts.abstract_locations let all c = c.options.Opts.all let emoji c = c.options.Opts.emoji diff --git a/src/commands/config/flowConfig.mli b/src/commands/config/flowConfig.mli index 45a21a30355..798c2b884b7 100644 --- a/src/commands/config/flowConfig.mli +++ b/src/commands/config/flowConfig.mli @@ -38,6 +38,7 @@ val includes: config -> string list val libs: config -> string list (* options *) +val libs_overrides: config -> bool val abstract_locations: config -> bool val all: config -> bool val emoji: config -> bool diff --git a/src/common/options.ml b/src/common/options.ml index 6ff71845b17..cc212e06004 100644 --- a/src/common/options.ml +++ b/src/common/options.ml @@ -58,6 +58,7 @@ type trust_mode = | SilentTrust type t = { + opt_libs_overrides : bool; opt_abstract_locations : bool; opt_all : bool; opt_debug : bool; @@ -119,6 +120,7 @@ type t = { opt_type_asserts: bool; } +let libs_overrides opts = opts.opt_libs_overrides let all opts = opts.opt_all let arch opts = opts.opt_arch let max_literal_length opts = opts.opt_max_literal_length diff --git a/src/flow_dot_js.ml b/src/flow_dot_js.ml index 0c346d4b5bb..d814e57d0a7 100644 --- a/src/flow_dot_js.ml +++ b/src/flow_dot_js.ml @@ -143,6 +143,7 @@ let stub_metadata ~root ~checked = { Context. include_suppressions = false; (* global *) + libs_overrides = false; max_literal_length = 100; enable_const_params = false; enable_enums = true; From a180e74470003742c645d6c49862ce7258f0d1af Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Thu, 11 Jul 2019 18:01:56 +0500 Subject: [PATCH 03/14] [services] Read libs in regular order when overrides option is enabled --- src/services/inference/init_js.ml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/services/inference/init_js.ml b/src/services/inference/init_js.ml index baeb4219d50..4e5e8aaa2bf 100644 --- a/src/services/inference/init_js.ml +++ b/src/services/inference/init_js.ml @@ -66,10 +66,17 @@ let parse_lib_file ~reader options file = let load_lib_files ~sig_cx ~options ~reader files = let verbose = Options.verbose options in + let libs_overrides = Options.libs_overrides options in + + let files = if libs_overrides then + files + else + List.rev files + in (* iterate in reverse override order *) let%lwt (_, result) = - List.rev files + files |> Lwt_list.fold_left_s ( fun (exclude_syms, results) file -> From a8d2c36389ec76bba24a571849f9e04f52fce6ea Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Thu, 11 Jul 2019 18:02:15 +0500 Subject: [PATCH 04/14] [typing] Add libs_overrides option to context --- src/typing/context.ml | 3 +++ src/typing/context.mli | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/typing/context.ml b/src/typing/context.ml index b07ecd26f83..3a72807f256 100644 --- a/src/typing/context.ml +++ b/src/typing/context.ml @@ -29,6 +29,7 @@ type metadata = { strict_local: bool; (* global *) + libs_overrides: bool; max_literal_length: int; enable_const_params: bool; enable_enums: bool; @@ -156,6 +157,7 @@ let metadata_of_options options = { strict_local = false; (* global *) + libs_overrides = Options.libs_overrides options; max_literal_length = Options.max_literal_length options; enable_const_params = Options.enable_const_params options; enable_enums = Options.enums options; @@ -271,6 +273,7 @@ let trust_constructor cx = cx.trust_constructor let cx_with_trust cx trust = { cx with trust_constructor = trust } let metadata cx = cx.metadata +let libs_overrides cx = cx.metadata.libs_overrides let max_literal_length cx = cx.metadata.max_literal_length let enable_const_params cx = cx.metadata.enable_const_params || cx.metadata.strict || cx.metadata.strict_local diff --git a/src/typing/context.mli b/src/typing/context.mli index 68c8b2cbf59..9351eac073b 100644 --- a/src/typing/context.mli +++ b/src/typing/context.mli @@ -29,6 +29,7 @@ type metadata = { strict: bool; strict_local: bool; (* global *) + libs_overrides: bool; max_literal_length: int; enable_const_params: bool; enable_enums: bool; @@ -71,6 +72,7 @@ val find_module_sig: sig_t -> string -> Type.t (* accessors *) val all_unresolved: t -> ISet.t IMap.t val metadata: t -> metadata +val libs_overrides: t -> bool val max_literal_length: t -> int val enable_const_params: t -> bool val enable_enums: t -> bool From 62c859c7642bbd56f7beb197cc3a9904b1804f02 Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Thu, 11 Jul 2019 18:02:57 +0500 Subject: [PATCH 05/14] [typing] Add OverwritePropT and MergeTypesT --- src/typing/debug_js.ml | 15 ++++++++++++++- src/typing/type.ml | 11 +++++++++++ src/typing/type_mapper.ml | 13 ++++++++++++- src/typing/type_visitor.ml | 10 ++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/typing/debug_js.ml b/src/typing/debug_js.ml index 32f561f763c..03395bb32cc 100644 --- a/src/typing/debug_js.ml +++ b/src/typing/debug_js.ml @@ -498,6 +498,7 @@ and _json_of_use_t_impl json_cx t = Hh_json.( ] | SetPropT (_, _, name, _, t, _) + | OverwritePropT (_, _, name, t) | GetPropT (_, _, name, t) | MatchPropT (_, _, name, t) | TestPropT (_, _, name, t) -> [ @@ -562,6 +563,11 @@ and _json_of_use_t_impl json_cx t = Hh_json.( "rightType", _json_of_t json_cx r ] + | MergeTypesT (_, _, _, _, l, r) -> [ + "leftType", _json_of_t json_cx l; + "rightType", _json_of_t json_cx r + ] + | ComparatorT (_, _, t) -> [ "type", _json_of_t json_cx t ] @@ -1797,7 +1803,7 @@ let rec dump_t_ (depth, tvars) cx t = | FunProtoT _ | FunProtoApplyT _ | FunProtoBindT _ - | FunProtoCallT _ + | FunProtoCallT _ | GlobalThisT _ -> p t | DefT (_, trust, PolyT (_, tps, c, id)) -> p ~trust:(Some trust) ~extra:(spf "%s [%s] #%d" (kid c) @@ -2099,6 +2105,9 @@ and dump_use_t_ (depth, tvars) cx t = (if Context.trust_tracking cx then string_of_trust_rep (lookup_trust cx) trust else "") (kid t) | UseT (use_op, t) -> spf "UseT (%s, %s)" (string_of_use_op use_op) (kid t) + | MergeTypesT (_, _, _, _, x, y) -> p ~extra:(spf "%s, %s" + (kid x) + (kid y)) t | AdderT (use_op, _, _, x, y) -> p ~extra:(spf "%s, %s, %s" (string_of_use_op use_op) (kid x) @@ -2231,6 +2240,10 @@ and dump_use_t_ (depth, tvars) cx t = (string_of_use_op use_op) (propref prop) (kid ptype)) t + | OverwritePropT (use_op, _, prop, ptype) -> p ~extra:(spf "%s, (%s), %s" + (string_of_use_op use_op) + (propref prop) + (kid ptype)) t | SetPrivatePropT (_, _, prop, _, _, ptype, _) -> p ~extra:(spf "(%s), %s" (prop) (kid ptype)) t diff --git a/src/typing/type.ml b/src/typing/type.ml index f5703706679..8e40382d6aa 100644 --- a/src/typing/type.ml +++ b/src/typing/type.ml @@ -365,6 +365,7 @@ module rec TypeTerm : sig | MethodT of use_op * (* call *) reason * (* lookup *) reason * propref * funcalltype * t option (* Similar to the last element of the MethodT *) | SetPropT of use_op * reason * propref * write_ctx * t * t option + | OverwritePropT of use_op * reason * propref * t (* The boolean flag indicates whether or not it is a static lookup. We cannot know this when * we generate the constraint, since the lower bound may be an unresolved OpenT. If it * resolves to a ClassT, we flip the flag to true, which causes us to check the private static @@ -400,6 +401,8 @@ module rec TypeTerm : sig | MixinT of reason * t | ToStringT of reason * use_t + | MergeTypesT of reason * bool (* flip *) * propref * t * t * t + (* overloaded +, could be subsumed by general overloading *) | AdderT of use_op * reason * bool * t * t (* overloaded relational operator, could be subsumed by general @@ -2174,6 +2177,7 @@ end = struct and reason_of_use_t = function | UseT (_, t) -> reason_of_t t | AdderT (_,reason,_,_,_) -> reason + | MergeTypesT (reason,_,_,_,_,_) -> reason | AndT (reason, _, _) -> reason | ArrRestT (_, reason, _, _) -> reason | AssertArithmeticOperandT reason -> reason @@ -2246,6 +2250,7 @@ end = struct | SentinelPropTestT (_, _, _, _, _, result) -> reason_of_t result | SetElemT (_,reason,_,_,_) -> reason | SetPropT (_,reason,_,_,_,_) -> reason + | OverwritePropT (_,reason,_,_) -> reason | SetPrivatePropT (_,reason,_,_,_,_,_) -> reason | SetProtoT (reason,_) -> reason | SpecializeT(_,_,reason,_,_,_) -> reason @@ -2333,6 +2338,7 @@ end = struct and mod_reason_of_use_t f = function | UseT (_, t) -> UseT (Op UnknownUse, mod_reason_of_t f t) | AdderT (use_op, reason, flip, rt, lt) -> AdderT (use_op, f reason, flip, rt, lt) + | MergeTypesT (reason, flip, propref, t, rt, lt) -> MergeTypesT (f reason, flip, propref, t, rt, lt) | AndT (reason, t1, t2) -> AndT (f reason, t1, t2) | ArrRestT (use_op, reason, i, t) -> ArrRestT (use_op, f reason, i, t) | AssertArithmeticOperandT reason -> AssertArithmeticOperandT (f reason) @@ -2423,6 +2429,7 @@ end = struct SentinelPropTestT (reason_op, l, key, sense, sentinel, mod_reason_of_t f result) | SetElemT (use_op, reason, it, et, t) -> SetElemT (use_op, f reason, it, et, t) | SetPropT (use_op, reason, n, i, t, tp) -> SetPropT (use_op, f reason, n, i, t, tp) + | OverwritePropT (use_op, reason, n, i) -> OverwritePropT (use_op, f reason, n, i) | SetPrivatePropT (use_op, reason, n, scopes, static, t, tp) -> SetPrivatePropT (use_op, f reason, n, scopes, static, t, tp) | SetProtoT (reason, t) -> SetProtoT (f reason, t) @@ -2477,6 +2484,7 @@ end = struct | CallT (op, r, f) -> util op (fun op -> CallT (op, r, f)) | MethodT (op, r1, r2, p, f, tm) -> util op (fun op -> MethodT (op, r1, r2, p, f, tm)) | SetPropT (op, r, p, w, t, tp) -> util op (fun op -> SetPropT (op, r, p, w, t, tp)) + | OverwritePropT (op, r, p, w) -> util op (fun op -> OverwritePropT (op, r, p, w)) | SetPrivatePropT (op, r, s, c, b, t, tp) -> util op (fun op -> SetPrivatePropT (op, r, s, c, b, t, tp)) | GetPropT (op, r, p, t) -> util op (fun op -> GetPropT (op, r, p, t)) @@ -2565,6 +2573,7 @@ end = struct | SubstOnPredT (_, _, _) | RefineT (_, _, _) | CondT (_, _, _, _) + | MergeTypesT (_, _, _, _, _, _) | ReactPropsToOut _ | ReactInToProps _ | DestructuringT _ @@ -3202,6 +3211,7 @@ let string_of_use_op_rec : use_op -> string = let string_of_use_ctor = function | UseT (op, t) -> spf "UseT(%s, %s)" (string_of_use_op op) (string_of_ctor t) + | MergeTypesT _ -> "MergeTypesT" | AdderT _ -> "AdderT" | AndT _ -> "AndT" | ArrRestT _ -> "ArrRestT" @@ -3295,6 +3305,7 @@ let string_of_use_ctor = function | SentinelPropTestT _ -> "SentinelPropTestT" | SetElemT _ -> "SetElemT" | SetPropT _ -> "SetPropT" + | OverwritePropT _ -> "OverwritePropT" | MatchPropT _ -> "MatchPropT" | SetPrivatePropT _ -> "SetPrivatePropT" | SetProtoT _ -> "SetProtoT" diff --git a/src/typing/type_mapper.ml b/src/typing/type_mapper.ml index d4b470fdd04..04e80751f62 100644 --- a/src/typing/type_mapper.ml +++ b/src/typing/type_mapper.ml @@ -107,7 +107,7 @@ class virtual ['a] t = object(self) | NullProtoT _ | FunProtoApplyT _ | FunProtoBindT _ - | FunProtoCallT _ + | FunProtoCallT _ | GlobalThisT _ -> t | AnyWithLowerBoundT t' -> let t'' = self#type_ cx map_cx t' in @@ -619,6 +619,11 @@ class virtual ['a] t_with_uses = object(self) let prop_t' = OptionUtils.ident_map (self#type_ cx map_cx) prop_t in if prop' == prop && t'' == t' && prop_t' == prop_t then t else SetPropT (use_op, r, prop', i, t'', prop_t') + | OverwritePropT (use_op, r, prop, t') -> + let prop' = self#prop_ref cx map_cx prop in + let t'' = self#type_ cx map_cx t' in + if prop' == prop && t'' == t' then t + else OverwritePropT (use_op, r, prop', t'') | SetPrivatePropT (use_op, r, prop, scopes, static, t', prop_t) -> let t'' = self#type_ cx map_cx t' in let scopes' = ListUtils.ident_map (self#class_binding cx map_cx) scopes in @@ -705,6 +710,12 @@ class virtual ['a] t_with_uses = object(self) let t'' = self#use_type cx map_cx t' in if t'' == t' then t else ToStringT (r, t'') + | MergeTypesT (r, flip, propref, t', t1, t2) -> + let t'' = self#type_ cx map_cx t' in + let t1' = self#type_ cx map_cx t1 in + let t2' = self#type_ cx map_cx t2 in + if t1' == t1 && t2' == t2 && t'' == t' then t + else MergeTypesT (r, flip, propref, t'', t1', t2') | AdderT (op, r, flip, t1, t2) -> let t1' = self#type_ cx map_cx t1 in let t2' = self#type_ cx map_cx t2 in diff --git a/src/typing/type_visitor.ml b/src/typing/type_visitor.ml index 7fc5319e6ed..d8a07a27947 100644 --- a/src/typing/type_visitor.ml +++ b/src/typing/type_visitor.ml @@ -280,6 +280,11 @@ class ['a] t = object(self) let acc = self#opt (self#type_ cx pole_TODO) acc prop_t in acc + | OverwritePropT (_, _, p, t) -> + let acc = self#propref cx acc p in + let acc = self#type_ cx pole_TODO acc t in + acc + | SetPropT (_, _, p, _, t, prop_t) -> let acc = self#propref cx acc p in let acc = self#type_ cx pole_TODO acc t in @@ -344,6 +349,11 @@ class ['a] t = object(self) | MixinT (_, t) -> self#type_ cx pole_TODO acc t | ToStringT (_, t) -> self#use_type_ cx acc t + | MergeTypesT (_, _, _, _, a, b) -> + let acc = self#type_ cx pole_TODO acc a in + let acc = self#type_ cx pole_TODO acc b in + acc + | AdderT (_, _, _, a, b) -> let acc = self#type_ cx pole_TODO acc a in let acc = self#type_ cx pole_TODO acc b in From 41267ac9d9e5db884f0a34b3ea89f12dbc744b83 Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Thu, 11 Jul 2019 18:03:13 +0500 Subject: [PATCH 06/14] [typing] Add OverwritePropH and MergeTypesH --- src/typing/sigHash.ml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/typing/sigHash.ml b/src/typing/sigHash.ml index 5a80dba0018..34299687193 100644 --- a/src/typing/sigHash.ml +++ b/src/typing/sigHash.ml @@ -87,6 +87,7 @@ type hash = | CallH | MethodH | SetPropH + | OverwritePropH | SetPrivatePropH | GetPropH | MatchPropH @@ -104,6 +105,7 @@ type hash = | SuperH | ImplementsH | MixinH + | MergeTypesH | AdderH | ComparatorH | UnaryMinusH @@ -248,6 +250,7 @@ let hash_of_use_ctor = Type.(function | CallT _ -> CallH | MethodT _ -> MethodH | SetPropT _ -> SetPropH + | OverwritePropT _ -> OverwritePropH | SetPrivatePropT _ -> SetPrivatePropH | GetPropT _ -> GetPropH | MatchPropT _ -> MatchPropH @@ -265,6 +268,7 @@ let hash_of_use_ctor = Type.(function | SuperT _ -> SuperH | ImplementsT _ -> ImplementsH | MixinT _ -> MixinH + | MergeTypesT _ -> MergeTypesH | AdderT _ -> AdderH | ComparatorT _ -> ComparatorH | UnaryMinusT _ -> UnaryMinusH From 6896a10d37ba56aa6416a99ff4909d25b601649e Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Thu, 11 Jul 2019 18:03:38 +0500 Subject: [PATCH 07/14] [typing] Disable excludes when libs_overrides is enabled --- src/typing/env.ml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/typing/env.ml b/src/typing/env.ml index e9423a8504d..01e7b8765c6 100644 --- a/src/typing/env.ml +++ b/src/typing/env.ml @@ -274,7 +274,9 @@ let trunc_env = (* initialize a new environment (once per module) *) let init_env ?(exclude_syms=SSet.empty) cx module_scope = - set_exclude_symbols exclude_syms; + if not (Context.libs_overrides cx) then + set_exclude_symbols exclude_syms; + havoc_current_activation (); let global_scope = Scope.fresh ~var_scope_kind:Global () in push_var_scope cx global_scope; From 7973a2252ba1d3aae5f3bab8644a255da44352c9 Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Thu, 11 Jul 2019 18:04:25 +0500 Subject: [PATCH 08/14] [typing] Add merging for classes and interfaces --- src/typing/flow_js.ml | 66 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/src/typing/flow_js.ml b/src/typing/flow_js.ml index a979825a8d4..1e338a29cf3 100644 --- a/src/typing/flow_js.ml +++ b/src/typing/flow_js.ml @@ -3732,6 +3732,9 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace = let reason = reason_of_t l in rec_flow cx trace (l, UseT (use_op, fix_this_class cx trace reason (r, i))) + | l, MergeTypesT (reason, flip, propref, original_t, r, u) -> + merge_builtin cx trace reason flip propref original_t l r u + (** This rule is hit when a polymorphic type appears outside a type application expression - i.e. not followed by a type argument list delimited by angle brackets. @@ -5244,6 +5247,10 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace = Option.iter ~f:(fun t -> rec_flow_t cx trace (AnyT.untyped reason_op, t)) prop_t; rec_flow cx trace (t, UseT (use_op, AnyT.untyped reason_op)) + | DefT (_, _, ObjT { props_tmap; _ }), OverwritePropT (_, _, Named (_, name), t) -> + let p = Field (None, t, Polarity.Neutral) in + Context.set_prop cx props_tmap name p; + | DefT (reason_obj, _, ObjT o), MatchPropT (use_op, reason_op, propref, proptype) -> match_obj_prop cx trace ~use_op o propref reason_obj reason_op proptype @@ -6524,7 +6531,7 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace = | GlobalThisT _, SetPropT (_, _, Named (_, name), _, tin, _) -> - set_builtin cx ~trace name tin; + overwrite_builtin cx ~trace name tin; | GlobalThisT _, _ -> let t = builtins cx in @@ -6940,6 +6947,7 @@ and empty_success flavor u = either by specially propagating it or selecting cases, etc. *) | _, UseT (_, ExactT _) | _, AdderT _ + | _, MergeTypesT _ | _, AndT _ | _, OrT _ (* Propagation cases: these cases don't use the fact that the LHS is @@ -7045,6 +7053,7 @@ and empty_success flavor u = | _, SetElemT _ | _, SetPrivatePropT _ | _, SetPropT _ + | _, OverwritePropT _ | _, SpecializeT _ | _, SubstOnPredT _ | _, SuperT _ @@ -7140,6 +7149,7 @@ and any_propagated cx trace any u = true | AdderT _ + | MergeTypesT _ | AndT _ | ArrRestT _ | BecomeT _ @@ -7200,6 +7210,7 @@ and any_propagated cx trace any u = | SentinelPropTestT _ | SetElemT _ | SetPropT _ + | OverwritePropT _ | ModuleExportsAssignT _ | SpecializeT _ | SubstOnPredT _ (* Should be impossible. We only generate these with OpenPredTs. *) @@ -11122,10 +11133,61 @@ and extract_non_spread cx ~trace = function add_output cx ~trace (Error_message.(EUnsupportedSyntax (loc, SpreadArgument))); AnyT.error reason +and merge_builtin cx trace reason flip propref original_t l r u = + let string_reason = string_of_reason reason in + ignore string_reason; + if needs_resolution r then begin + (* TODO: this doesn't work without writing to property first *) + rec_flow cx trace (u, OverwritePropT (unknown_use, reason, propref, l)); + (* *) + + rec_flow cx trace (r, MergeTypesT (reason, not flip, propref, original_t, l, u)) + end else begin + let (l, r) = if flip then (r, l) else (l, r) in + begin match l, r with + + (* polymorphic interface ~> polymorphic class *) + | DefT (_, _, PolyT (_, _, DefT (_, _, ClassT (DefT (_, _, InstanceT (_, _, _, { structural = true; own_props = o1_id; _ })))), _)), + DefT (_, _, PolyT (_, _, ThisClassT (_, DefT (_, _, InstanceT (_, _, _, { structural = false; own_props = o2_id; _ }))), _)) -> + let o1 = Context.find_props cx o1_id in + let o2 = Context.find_props cx o2_id in + ignore o1; + ignore o2; + Context.add_property_map cx o2_id (SMap.union o1 o2); + + (* interface ~> class *) + | DefT (_, _, ClassT (DefT (_, _, InstanceT (_, _, _, { structural = true; own_props = o1_id; _ })))), + ThisClassT (_, DefT (_, _, InstanceT (_, _, _, { structural = false; own_props = o2_id; _ }))) -> + let o1 = Context.find_props cx o1_id in + let o2 = Context.find_props cx o2_id in + ignore o1; + ignore o2; + Context.add_property_map cx o2_id (SMap.union o1 o2); + + (* any ~> any *) + | _, _ -> + () + end + end + and set_builtin cx ?trace x t = + let reason = builtin_reason (RCustom x) in + let obj = builtins cx in + let propref = Named (reason, x) in + let old_t = Tvar.mk_derivable_where cx reason (fun t -> + flow_opt cx ?trace (obj, GetPropT (unknown_use, reason, propref, t)); + ) + in + if Context.libs_overrides cx then + flow_opt cx ?trace (t, MergeTypesT (reason, false, propref, t, old_t, obj)) + else + flow_opt cx ?trace (obj, SetPropT (unknown_use, reason, propref, Normal, t, None)) + +and overwrite_builtin cx ?trace x t = let reason = builtin_reason (RCustom x) in let propref = Named (reason, x) in - flow_opt cx ?trace (builtins cx, SetPropT (unknown_use, reason, propref, Normal, t, None)) + let obj = builtins cx in + flow_opt cx ?trace (obj, OverwritePropT (unknown_use, reason, propref, t)) (* Wrapper functions around __flow that manage traces. Use these functions for all recursive calls in the implementation of __flow. *) From cfdb4bddd783ab30f984399a236a909cf0d2ec5e Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Thu, 11 Jul 2019 18:15:28 +0500 Subject: [PATCH 09/14] [typing] Rename libs_overrides to declaration_merging --- src/commands/commandUtils.ml | 2 +- src/commands/config/flowConfig.ml | 10 +++++----- src/commands/config/flowConfig.mli | 2 +- src/common/options.ml | 2 +- src/flow_dot_js.ml | 2 +- src/services/inference/init_js.ml | 4 ++-- src/typing/context.ml | 6 +++--- src/typing/context.mli | 4 ++-- src/typing/env.ml | 2 +- src/typing/flow_js.ml | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/commands/commandUtils.ml b/src/commands/commandUtils.ml index ff5ac101b0c..e7565d167ac 100644 --- a/src/commands/commandUtils.ml +++ b/src/commands/commandUtils.ml @@ -1095,7 +1095,7 @@ let make_options ~flowconfig_name ~flowconfig ~lazy_mode ~root (options_flags: O opt_no_saved_state = options_flags.no_saved_state; opt_arch; opt_abstract_locations; - opt_libs_overrides = FlowConfig.libs_overrides flowconfig; + opt_declaration_merging = FlowConfig.declaration_merging flowconfig; opt_include_suppressions = options_flags.include_suppressions; opt_trust_mode = Option.value options_flags.trust_mode ~default:(FlowConfig.trust_mode flowconfig); opt_recursion_limit = FlowConfig.recursion_limit flowconfig; diff --git a/src/commands/config/flowConfig.ml b/src/commands/config/flowConfig.ml index 635507fefe1..c2ff410bab0 100644 --- a/src/commands/config/flowConfig.ml +++ b/src/commands/config/flowConfig.ml @@ -43,7 +43,7 @@ module Opts = struct type opt_error = int * error_kind type t = { - libs_overrides: bool; + declaration_merging: bool; abstract_locations: bool; all: bool; emoji: bool; @@ -135,7 +135,7 @@ module Opts = struct |> SSet.add ".webm" let default_options = { - libs_overrides = false; + declaration_merging = false; abstract_locations = false; all = false; emoji = false; @@ -619,8 +619,8 @@ module Opts = struct "experimental.abstract_locations", boolean (fun opts v -> Ok { opts with abstract_locations = v }); - "experimental.libs_overrides", - boolean (fun opts v -> Ok { opts with libs_overrides = v }); + "experimental.declaration_merging", + boolean (fun opts v -> Ok { opts with declaration_merging = v }); "no_flowlib", boolean (fun opts v -> Ok { opts with no_flowlib = v }); @@ -1019,7 +1019,7 @@ let includes config = config.includes let libs config = config.libs (* options *) -let libs_overrides c = c.options.Opts.libs_overrides +let declaration_merging c = c.options.Opts.declaration_merging let abstract_locations c = c.options.Opts.abstract_locations let all c = c.options.Opts.all let emoji c = c.options.Opts.emoji diff --git a/src/commands/config/flowConfig.mli b/src/commands/config/flowConfig.mli index 798c2b884b7..2f46e7aa062 100644 --- a/src/commands/config/flowConfig.mli +++ b/src/commands/config/flowConfig.mli @@ -38,7 +38,7 @@ val includes: config -> string list val libs: config -> string list (* options *) -val libs_overrides: config -> bool +val declaration_merging: config -> bool val abstract_locations: config -> bool val all: config -> bool val emoji: config -> bool diff --git a/src/common/options.ml b/src/common/options.ml index cc212e06004..8b832ec4365 100644 --- a/src/common/options.ml +++ b/src/common/options.ml @@ -120,7 +120,7 @@ type t = { opt_type_asserts: bool; } -let libs_overrides opts = opts.opt_libs_overrides +let declaration_merging opts = opts.opt_declaration_merging let all opts = opts.opt_all let arch opts = opts.opt_arch let max_literal_length opts = opts.opt_max_literal_length diff --git a/src/flow_dot_js.ml b/src/flow_dot_js.ml index d814e57d0a7..cf2441bf31c 100644 --- a/src/flow_dot_js.ml +++ b/src/flow_dot_js.ml @@ -143,7 +143,7 @@ let stub_metadata ~root ~checked = { Context. include_suppressions = false; (* global *) - libs_overrides = false; + declaration_merging = false; max_literal_length = 100; enable_const_params = false; enable_enums = true; diff --git a/src/services/inference/init_js.ml b/src/services/inference/init_js.ml index 4e5e8aaa2bf..dd13c6f0b90 100644 --- a/src/services/inference/init_js.ml +++ b/src/services/inference/init_js.ml @@ -66,9 +66,9 @@ let parse_lib_file ~reader options file = let load_lib_files ~sig_cx ~options ~reader files = let verbose = Options.verbose options in - let libs_overrides = Options.libs_overrides options in + let declaration_merging = Options.declaration_merging options in - let files = if libs_overrides then + let files = if declaration_merging then files else List.rev files diff --git a/src/typing/context.ml b/src/typing/context.ml index 3a72807f256..d321ed66f3e 100644 --- a/src/typing/context.ml +++ b/src/typing/context.ml @@ -29,7 +29,7 @@ type metadata = { strict_local: bool; (* global *) - libs_overrides: bool; + declaration_merging: bool; max_literal_length: int; enable_const_params: bool; enable_enums: bool; @@ -157,7 +157,7 @@ let metadata_of_options options = { strict_local = false; (* global *) - libs_overrides = Options.libs_overrides options; + declaration_merging = Options.declaration_merging options; max_literal_length = Options.max_literal_length options; enable_const_params = Options.enable_const_params options; enable_enums = Options.enums options; @@ -273,7 +273,7 @@ let trust_constructor cx = cx.trust_constructor let cx_with_trust cx trust = { cx with trust_constructor = trust } let metadata cx = cx.metadata -let libs_overrides cx = cx.metadata.libs_overrides +let declaration_merging cx = cx.metadata.declaration_merging let max_literal_length cx = cx.metadata.max_literal_length let enable_const_params cx = cx.metadata.enable_const_params || cx.metadata.strict || cx.metadata.strict_local diff --git a/src/typing/context.mli b/src/typing/context.mli index 9351eac073b..29af57a8ef9 100644 --- a/src/typing/context.mli +++ b/src/typing/context.mli @@ -29,7 +29,7 @@ type metadata = { strict: bool; strict_local: bool; (* global *) - libs_overrides: bool; + declaration_merging: bool; max_literal_length: int; enable_const_params: bool; enable_enums: bool; @@ -72,7 +72,7 @@ val find_module_sig: sig_t -> string -> Type.t (* accessors *) val all_unresolved: t -> ISet.t IMap.t val metadata: t -> metadata -val libs_overrides: t -> bool +val declaration_merging: t -> bool val max_literal_length: t -> int val enable_const_params: t -> bool val enable_enums: t -> bool diff --git a/src/typing/env.ml b/src/typing/env.ml index 01e7b8765c6..ad1eebb41d4 100644 --- a/src/typing/env.ml +++ b/src/typing/env.ml @@ -274,7 +274,7 @@ let trunc_env = (* initialize a new environment (once per module) *) let init_env ?(exclude_syms=SSet.empty) cx module_scope = - if not (Context.libs_overrides cx) then + if not (Context.declaration_merging cx) then set_exclude_symbols exclude_syms; havoc_current_activation (); diff --git a/src/typing/flow_js.ml b/src/typing/flow_js.ml index 1e338a29cf3..9fb16faed00 100644 --- a/src/typing/flow_js.ml +++ b/src/typing/flow_js.ml @@ -11178,7 +11178,7 @@ and set_builtin cx ?trace x t = flow_opt cx ?trace (obj, GetPropT (unknown_use, reason, propref, t)); ) in - if Context.libs_overrides cx then + if Context.declaration_merging cx then flow_opt cx ?trace (t, MergeTypesT (reason, false, propref, t, old_t, obj)) else flow_opt cx ?trace (obj, SetPropT (unknown_use, reason, propref, Normal, t, None)) From b0d46585cab1d526da2636718ad8ebb117cecfe3 Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Thu, 11 Jul 2019 18:17:18 +0500 Subject: [PATCH 10/14] [common] Rename libs_overrides to declaration_merging --- src/common/options.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/options.ml b/src/common/options.ml index 8b832ec4365..dac1f311346 100644 --- a/src/common/options.ml +++ b/src/common/options.ml @@ -58,7 +58,7 @@ type trust_mode = | SilentTrust type t = { - opt_libs_overrides : bool; + opt_declaration_merging : bool; opt_abstract_locations : bool; opt_all : bool; opt_debug : bool; From 532caab24fa821ce31a75a7e2efb68948bb41e25 Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Thu, 11 Jul 2019 18:27:04 +0500 Subject: [PATCH 11/14] [tests] Add declaration merging tests --- tests/lib_declaration_merging/.flowconfig | 3 +++ tests/lib_declaration_merging/flow-typed/foo.js | 5 +++++ tests/lib_declaration_merging/flow-typed/override.js | 9 +++++++++ tests/lib_declaration_merging/index.js | 12 ++++++++++++ 4 files changed, 29 insertions(+) create mode 100644 tests/lib_declaration_merging/.flowconfig create mode 100644 tests/lib_declaration_merging/flow-typed/foo.js create mode 100644 tests/lib_declaration_merging/flow-typed/override.js create mode 100644 tests/lib_declaration_merging/index.js diff --git a/tests/lib_declaration_merging/.flowconfig b/tests/lib_declaration_merging/.flowconfig new file mode 100644 index 00000000000..8ed8835814e --- /dev/null +++ b/tests/lib_declaration_merging/.flowconfig @@ -0,0 +1,3 @@ +[options] +no_flowlib=true +experimental.declaration_merging=true diff --git a/tests/lib_declaration_merging/flow-typed/foo.js b/tests/lib_declaration_merging/flow-typed/foo.js new file mode 100644 index 00000000000..e1abbb07fed --- /dev/null +++ b/tests/lib_declaration_merging/flow-typed/foo.js @@ -0,0 +1,5 @@ +declare module "wat" { + declare class Bar { + foo: number; + } +} diff --git a/tests/lib_declaration_merging/flow-typed/override.js b/tests/lib_declaration_merging/flow-typed/override.js new file mode 100644 index 00000000000..58e95992b31 --- /dev/null +++ b/tests/lib_declaration_merging/flow-typed/override.js @@ -0,0 +1,9 @@ +interface Array { + bar: string; +} + +declare module 'wat' { + declare interface Bar { + bar: string; + } +} diff --git a/tests/lib_declaration_merging/index.js b/tests/lib_declaration_merging/index.js new file mode 100644 index 00000000000..2cbf4fabf9f --- /dev/null +++ b/tests/lib_declaration_merging/index.js @@ -0,0 +1,12 @@ +// @flow + +import { Bar } from "wat"; + +declare var wat: Bar; + +wat.foo; // doesn't work, but probably should, maybe not +wat.bar; + +const foo = [1, 2, 3]; + +(foo.bar: string); // ok From 41f018c6bfc4a0fd3c1043b559a4810cf4054ce7 Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Mon, 22 Jul 2019 10:47:57 +0500 Subject: [PATCH 12/14] [typing] Add `declare module` augmentation --- src/typing/flow_js.ml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/typing/flow_js.ml b/src/typing/flow_js.ml index 9fb16faed00..200f0c10812 100644 --- a/src/typing/flow_js.ml +++ b/src/typing/flow_js.ml @@ -5251,6 +5251,9 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace = let p = Field (None, t, Polarity.Neutral) in Context.set_prop cx props_tmap name p; + | ModuleT (_, { exports_tmap; _ }, _), OverwritePropT (_, _, Named (_, name), t) -> + Context.set_export cx exports_tmap name (None, t); + | DefT (reason_obj, _, ObjT o), MatchPropT (use_op, reason_op, propref, proptype) -> match_obj_prop cx trace ~use_op o propref reason_obj reason_op proptype @@ -11164,6 +11167,18 @@ and merge_builtin cx trace reason flip propref original_t l r u = ignore o2; Context.add_property_map cx o2_id (SMap.union o1 o2); + (* module ~> module *) + | ModuleT (_, {exports_tmap = exports1_id; _}, _), ModuleT (_, {exports_tmap = exports2_id; _}, _) -> + let exports1 = Context.find_exports cx exports1_id in + let exports2 = Context.find_exports cx exports2_id in + let exports = SMap.union exports1 exports2 in + Context.add_export_map cx exports2_id exports; + ignore @@ SMap.union ~combine:(fun key (_, t1) (_, t2) -> + rec_flow cx trace (t2, MergeTypesT (reason, false, Named (reason_of_t t1, key), t2, t1, r)); + None + ) exports1 exports2; + () + (* any ~> any *) | _, _ -> () From 6efaafd2f66a81d4afb461a139f937579f958fa2 Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Mon, 22 Jul 2019 10:52:13 +0500 Subject: [PATCH 13/14] [tests] Add `declare module` test --- tests/lib_declaration_merging/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/lib_declaration_merging/index.js b/tests/lib_declaration_merging/index.js index 2cbf4fabf9f..6252c1ae62c 100644 --- a/tests/lib_declaration_merging/index.js +++ b/tests/lib_declaration_merging/index.js @@ -4,8 +4,8 @@ import { Bar } from "wat"; declare var wat: Bar; -wat.foo; // doesn't work, but probably should, maybe not -wat.bar; +;(wat.foo: number); // ok +;(wat.bar: string); // ok const foo = [1, 2, 3]; From 3b28a362692425164474a2f16f17aad295d8f208 Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Mon, 22 Jul 2019 11:01:02 +0500 Subject: [PATCH 14/14] [tests] Add more tests --- .../flow-typed/{foo.js => 00_wat_module.js} | 2 ++ .../flow-typed/array_override.js | 3 +++ .../flow-typed/foo_override.js | 6 ++++++ .../flow-typed/override.js | 4 +--- .../lib_declaration_merging.exp | 16 ++++++++++++++++ .../node_modules/foo/index.js.flow | 7 +++++++ .../node_modules/foo/package.json | 4 ++++ .../lib_declaration_merging/test_node_modules.js | 10 ++++++++++ 8 files changed, 49 insertions(+), 3 deletions(-) rename tests/lib_declaration_merging/flow-typed/{foo.js => 00_wat_module.js} (57%) create mode 100644 tests/lib_declaration_merging/flow-typed/array_override.js create mode 100644 tests/lib_declaration_merging/flow-typed/foo_override.js create mode 100644 tests/lib_declaration_merging/lib_declaration_merging.exp create mode 100644 tests/lib_declaration_merging/node_modules/foo/index.js.flow create mode 100644 tests/lib_declaration_merging/node_modules/foo/package.json create mode 100644 tests/lib_declaration_merging/test_node_modules.js diff --git a/tests/lib_declaration_merging/flow-typed/foo.js b/tests/lib_declaration_merging/flow-typed/00_wat_module.js similarity index 57% rename from tests/lib_declaration_merging/flow-typed/foo.js rename to tests/lib_declaration_merging/flow-typed/00_wat_module.js index e1abbb07fed..c61fe55c133 100644 --- a/tests/lib_declaration_merging/flow-typed/foo.js +++ b/tests/lib_declaration_merging/flow-typed/00_wat_module.js @@ -1,3 +1,5 @@ +// This would fail if order of files is different + declare module "wat" { declare class Bar { foo: number; diff --git a/tests/lib_declaration_merging/flow-typed/array_override.js b/tests/lib_declaration_merging/flow-typed/array_override.js new file mode 100644 index 00000000000..aba8794592b --- /dev/null +++ b/tests/lib_declaration_merging/flow-typed/array_override.js @@ -0,0 +1,3 @@ +interface Array { + bar: string; +} diff --git a/tests/lib_declaration_merging/flow-typed/foo_override.js b/tests/lib_declaration_merging/flow-typed/foo_override.js new file mode 100644 index 00000000000..e38fd66a634 --- /dev/null +++ b/tests/lib_declaration_merging/flow-typed/foo_override.js @@ -0,0 +1,6 @@ +declare module 'foo' { + // Doesn't work since Node.js modules are orthogonal to `declare module` + declare export interface Foo { + b: string; + } +} diff --git a/tests/lib_declaration_merging/flow-typed/override.js b/tests/lib_declaration_merging/flow-typed/override.js index 58e95992b31..f7ad9abb273 100644 --- a/tests/lib_declaration_merging/flow-typed/override.js +++ b/tests/lib_declaration_merging/flow-typed/override.js @@ -1,6 +1,4 @@ -interface Array { - bar: string; -} +// This would fail if order of files is different declare module 'wat' { declare interface Bar { diff --git a/tests/lib_declaration_merging/lib_declaration_merging.exp b/tests/lib_declaration_merging/lib_declaration_merging.exp new file mode 100644 index 00000000000..41a36506ef7 --- /dev/null +++ b/tests/lib_declaration_merging/lib_declaration_merging.exp @@ -0,0 +1,16 @@ +Error ----------------------------------------------------------------------------------------- test_node_modules.js:8:1 + +Cannot get `foo.b` because property `b` is missing in `Foo` [1]. + + test_node_modules.js:8:1 + 8| foo.b; // error + ^^^^^ + +References: + test_node_modules.js:5:18 + 5| declare var foo: Foo; + ^^^ [1] + + + +Found 1 error diff --git a/tests/lib_declaration_merging/node_modules/foo/index.js.flow b/tests/lib_declaration_merging/node_modules/foo/index.js.flow new file mode 100644 index 00000000000..719cf9a9ce0 --- /dev/null +++ b/tests/lib_declaration_merging/node_modules/foo/index.js.flow @@ -0,0 +1,7 @@ +// @flow + +// Node.js module + +declare export class Foo { + a: number; +} diff --git a/tests/lib_declaration_merging/node_modules/foo/package.json b/tests/lib_declaration_merging/node_modules/foo/package.json new file mode 100644 index 00000000000..3a8d4114836 --- /dev/null +++ b/tests/lib_declaration_merging/node_modules/foo/package.json @@ -0,0 +1,4 @@ +{ + "name": "foo", + "main": "./index.js.flow" +} diff --git a/tests/lib_declaration_merging/test_node_modules.js b/tests/lib_declaration_merging/test_node_modules.js new file mode 100644 index 00000000000..8321b2c98d2 --- /dev/null +++ b/tests/lib_declaration_merging/test_node_modules.js @@ -0,0 +1,10 @@ +// @flow + +import {Foo} from 'foo' + +declare var foo: Foo; + +foo.a; + +// Doesn't work since Node.js modules are orthogonal to `declare module` +foo.b; // error