Skip to content

Commit

Permalink
[flow] Scoped libdef support 5/n: Error on libdef module override
Browse files Browse the repository at this point in the history
Summary:
Same as last diffs, but for modules.

Changelog: [errors] Overriding already defined modules in library definition will now error.

Reviewed By: panagosg7

Differential Revision: D70575060

fbshipit-source-id: 72edd21a089e2b30319cc3c28103b6239f9288dc
  • Loading branch information
SamChou19815 authored and facebook-github-bot committed Mar 7, 2025
1 parent 10e2d16 commit ff3e286
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 5 deletions.
7 changes: 6 additions & 1 deletion src/parser_utils/type_sig/__tests__/type_sig_tests.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4657,7 +4657,12 @@ let%expect_test "builtin_cjs_ignore_later" =
info =
CJSModuleInfo {type_export_keys = [||];
type_stars = []; strict = true;
platform_availability_set = None}} |}]
platform_availability_set = None}}
Errors:
(BindingValidationError
Signature_error.ModuleOverride {
name = "foo"; override_binding_loc = [2:15-18];
existing_binding_loc = [5:15-18]}) |}]

let%expect_test "builtin_cjs_module_auto_export_type" =
(* All types in cjs modules are auto exported. *)
Expand Down
12 changes: 9 additions & 3 deletions src/parser_utils/type_sig/type_sig_parse.ml
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ module Scope = struct
let push_declare_namespace parent =
DeclareNamespace { parent; values = SMap.empty; types = SMap.empty }

let push_declare_module loc name parent =
let push_declare_module loc name parent tbls =
let exports = Exports.create ~strict:true ~platform_availability_set:None in
begin
match parent with
Expand All @@ -554,7 +554,13 @@ module Scope = struct
name
(function
| None -> Some (loc, exports)
| Some existing -> Some existing)
| Some existing ->
let override_binding_loc = fst existing in
tbls.additional_errors <-
Signature_error.ModuleOverride
{ name; override_binding_loc; existing_binding_loc = loc }
:: tbls.additional_errors;
Some existing)
g.modules
| _ -> ()
end;
Expand Down Expand Up @@ -4824,7 +4830,7 @@ let rec statement opts scope tbls (loc, stmt) =
| S.DeclareModule.Literal (id_loc, { Ast.StringLiteral.value; _ }) ->
(push_loc tbls id_loc, value)
in
let scope = Scope.push_declare_module loc name scope in
let scope = Scope.push_declare_module loc name scope tbls in
let (_, { S.Block.body = stmts; comments = _ }) = body in
let visit_statement ((_, stmt') as stmt) =
match
Expand Down
28 changes: 27 additions & 1 deletion tests/duplicate_libs/duplicate_libs.exp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ surprising behaviors. [libdef-override]
^^^^^^^^^^ [1]


Error ------------------------------------------------------------------------------------------- lib/shared/lib.js:5:16

This module declaration overrides an existing module `bar` [1]. Overriding in library definitions can lead to surprising
behaviors. [libdef-override]

5| declare module 'bar' {
^^^^^ [1]


Error ------------------------------------------------------------------------------------------------------ test.js:1:2

Cannot cast `global_foo` to string because number [1] is incompatible with string [2]. [incompatible-cast]
Expand All @@ -24,5 +33,22 @@ References:
^^^^^^ [2]


Error ------------------------------------------------------------------------------------------------------ test.js:2:2

Cannot cast `require(...)` to number because string [1] is incompatible with number [2]. [incompatible-cast]

test.js:2:2
2| (require('bar'): number); // error: string ~> number
^^^^^^^^^^^^^^

References:
lib/shared/lib.js:6:27
6| declare module.exports: string;
^^^^^^ [1]
test.js:2:18
2| (require('bar'): number); // error: string ~> number
^^^^^^ [2]



Found 2 errors
Found 4 errors
4 changes: 4 additions & 0 deletions tests/duplicate_libs/lib/shared/lib.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// The lib file is included twice, because it is included in both `lib` and
// `lib/shared`, which are both listed in the `.flowconfig`
declare var global_foo: number; // intentional-libdef-override

declare module 'bar' {
declare module.exports: string;
}
1 change: 1 addition & 0 deletions tests/duplicate_libs/test.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
(global_foo: string); // error: number ~> string
(require('bar'): number); // error: string ~> number

0 comments on commit ff3e286

Please sign in to comment.