Skip to content

Commit

Permalink
[flow] More permissive what's allowed in declare namespace and declar…
Browse files Browse the repository at this point in the history
…e module

Summary:
Right now, Flow complains about `export type` and `export interface` in `declare module` and `declare namespace` for no good reason. It is mostly a leftover of the past when the parser only permits `declare` statements in these body. This diff removes the restriction from Flow.

Changelog: [feature] `export type Foo = ...` and `export interface Bar {...}` statements are now allowed in `declare module` and `declare namespace` bodies.

Reviewed By: panagosg7

Differential Revision: D54989486

fbshipit-source-id: 5d27b88df2f6cde02cb8754c65589bb5dbba2fbd
  • Loading branch information
SamChou19815 authored and facebook-github-bot committed Mar 19, 2024
1 parent cbd056f commit 518a328
Show file tree
Hide file tree
Showing 11 changed files with 352 additions and 157 deletions.
90 changes: 47 additions & 43 deletions src/parser/flow_ast_utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -215,56 +215,60 @@ let is_super_member_access = function
| { Flow_ast.Expression.Member._object = (_, Flow_ast.Expression.Super _); _ } -> true
| _ -> false

let acceptable_statement_in_declaration_context ~in_declare_namespace = function
| Flow_ast.Statement.Block _ -> Error "block"
| Flow_ast.Statement.Break _ -> Error "break"
| Flow_ast.Statement.ClassDeclaration _ -> Error "class declaration"
| Flow_ast.Statement.ComponentDeclaration _ -> Error "component declaration"
| Flow_ast.Statement.Continue _ -> Error "continue"
| Flow_ast.Statement.Debugger _ -> Error "debugger"
| Flow_ast.Statement.DoWhile _ -> Error "do while"
| Flow_ast.Statement.ExportDefaultDeclaration _ -> Error "export"
| Flow_ast.Statement.ExportNamedDeclaration _ -> Error "export"
| Flow_ast.Statement.Expression _ -> Error "expression"
| Flow_ast.Statement.For _ -> Error "for"
| Flow_ast.Statement.ForIn _ -> Error "for in"
| Flow_ast.Statement.ForOf _ -> Error "for of"
| Flow_ast.Statement.FunctionDeclaration _ -> Error "function declaration"
| Flow_ast.Statement.If _ -> Error "if"
| Flow_ast.Statement.Labeled _ -> Error "labeled"
| Flow_ast.Statement.Return _ -> Error "return"
| Flow_ast.Statement.Switch _ -> Error "switch"
| Flow_ast.Statement.Throw _ -> Error "throw"
| Flow_ast.Statement.Try _ -> Error "try"
| Flow_ast.Statement.VariableDeclaration _ -> Error "variable declaration"
| Flow_ast.Statement.While _ -> Error "while"
| Flow_ast.Statement.With _ -> Error "with"
| Flow_ast.Statement.ImportDeclaration _ ->
let acceptable_statement_in_declaration_context ~in_declare_namespace =
let open Flow_ast.Statement in
function
| Block _ -> Error "block"
| Break _ -> Error "break"
| ClassDeclaration _ -> Error "class declaration"
| ComponentDeclaration _ -> Error "component declaration"
| Continue _ -> Error "continue"
| Debugger _ -> Error "debugger"
| DoWhile _ -> Error "do while"
| ExportDefaultDeclaration _ -> Error "export default"
| ExportNamedDeclaration { ExportNamedDeclaration.export_kind = ExportValue; _ } ->
Error "value export"
| Expression _ -> Error "expression"
| For _ -> Error "for"
| ForIn _ -> Error "for in"
| ForOf _ -> Error "for of"
| FunctionDeclaration _ -> Error "function declaration"
| If _ -> Error "if"
| Labeled _ -> Error "labeled"
| Return _ -> Error "return"
| Switch _ -> Error "switch"
| Throw _ -> Error "throw"
| Try _ -> Error "try"
| VariableDeclaration _ -> Error "variable declaration"
| While _ -> Error "while"
| With _ -> Error "with"
| ImportDeclaration _ ->
if in_declare_namespace then
Error "import declaration"
else
Ok ()
| Flow_ast.Statement.DeclareModuleExports _ ->
| DeclareModuleExports _ ->
if in_declare_namespace then
Error "declare module.exports"
else
Ok ()
| Flow_ast.Statement.DeclareClass _
| Flow_ast.Statement.DeclareComponent _
| Flow_ast.Statement.DeclareEnum _
| Flow_ast.Statement.DeclareExportDeclaration _
| Flow_ast.Statement.DeclareFunction _
| Flow_ast.Statement.DeclareInterface _
| Flow_ast.Statement.DeclareModule _
| Flow_ast.Statement.DeclareNamespace _
| Flow_ast.Statement.DeclareOpaqueType _
| Flow_ast.Statement.DeclareTypeAlias _
| Flow_ast.Statement.DeclareVariable _
| Flow_ast.Statement.Empty _
| Flow_ast.Statement.EnumDeclaration _
| Flow_ast.Statement.InterfaceDeclaration _
| Flow_ast.Statement.OpaqueType _
| Flow_ast.Statement.TypeAlias _ ->
| DeclareClass _
| DeclareComponent _
| DeclareEnum _
| DeclareExportDeclaration _
| DeclareFunction _
| DeclareInterface _
| DeclareModule _
| DeclareNamespace _
| DeclareOpaqueType _
| DeclareTypeAlias _
| DeclareVariable _
| Empty _
| EnumDeclaration _
| ExportNamedDeclaration { ExportNamedDeclaration.export_kind = ExportType; _ }
| InterfaceDeclaration _
| OpaqueType _
| TypeAlias _ ->
Ok ()

let rec is_type_only_declaration_statement (_, stmt') =
Expand All @@ -284,6 +288,7 @@ let rec is_type_only_declaration_statement (_, stmt') =
true
| DeclareNamespace { DeclareNamespace.body = (_, { Block.body; _ }); _ } ->
List.for_all is_type_only_declaration_statement body
| ExportNamedDeclaration { ExportNamedDeclaration.export_kind; _ } -> export_kind = ExportType
| Block _
| Break _
| ClassDeclaration _
Expand All @@ -293,7 +298,6 @@ let rec is_type_only_declaration_statement (_, stmt') =
| DoWhile _
| EnumDeclaration _
| ExportDefaultDeclaration _
| ExportNamedDeclaration _
| Expression _
| For _
| ForIn _
Expand Down
35 changes: 25 additions & 10 deletions src/parser_utils/type_sig/__tests__/type_sig_tests.ml
Original file line number Diff line number Diff line change
Expand Up @@ -5566,19 +5566,25 @@ let%expect_test "builtin_cjs_module_auto_export_type" =
(* All types in cjs modules are auto exported. *)
print_builtins [{|
declare module foo {
declare type T = number;
declare type T1 = number;
export type T2 = string;
declare module.exports: string;
}
|}];
[%expect {|
Local defs:
0. TypeAlias {id_loc = [2:15-16]; name = "T"; tparams = Mono; body = (Annot (Number [2:19-25]))}
0. TypeAlias {id_loc = [2:15-17];
name = "T1"; tparams = Mono;
body = (Annot (Number [2:20-26]))}
1. TypeAlias {id_loc = [3:14-16];
name = "T2"; tparams = Mono;
body = (Annot (String [3:19-25]))}

Builtin module foo:
[1:15-18] CJSModule {type_exports = [|(ExportTypeBinding 0)|];
exports = (Some (Annot (String [3:26-32])));
[1:15-18] CJSModule {type_exports = [|(ExportTypeBinding 0); (ExportTypeBinding 1)|];
exports = (Some (Annot (String [4:26-32])));
info =
CJSModuleInfo {type_export_keys = [|"T"|];
CJSModuleInfo {type_export_keys = [|"T1"; "T2"|];
type_stars = []; strict = true;
platform_availability_set = None}} |}]

Expand Down Expand Up @@ -5667,6 +5673,7 @@ let%expect_test "builtin_cjs_module_with_implicit_exports" =
declare enum A { B }
declare type T = number;
declare export type U = string;
export const ignored = 3; // unsupported;
}
|}];
[%expect {|
Expand Down Expand Up @@ -5881,11 +5888,14 @@ let%expect_test "builtin_declare_namespace" =
declare function f(): string;
declare function f(): number;
declare type Baz = string;
export type Boz = string;
enum B {
C,
D,
}
if (true) {} // unsupported
export const foo = ''; // unsupported
export default foo; // unsupported
declare module.exports: {foo: string}; // unsupported
import React from 'react'; // unsupported
}
Expand All @@ -5912,19 +5922,24 @@ let%expect_test "builtin_declare_namespace" =
4. TypeAlias {id_loc = [7:15-18];
name = "Baz"; tparams = Mono;
body = (Annot (String [7:21-27]))}
5. EnumBinding {id_loc = [8:7-8];
5. TypeAlias {id_loc = [8:14-17];
name = "Boz"; tparams = Mono;
body = (Annot (String [8:20-26]))}
6. EnumBinding {id_loc = [9:7-8];
name = "B"; rep = StringRep {truthy = true};
members = { "C" -> [9:4-5]; "D" -> [10:4-5] };
members = { "C" -> [10:4-5]; "D" -> [11:4-5] };
has_unknown_members = false}
6. NamespaceBinding {id_loc = [1:18-20];
7. NamespaceBinding {id_loc = [1:18-20];
name = "ns";
values =
{ "B" -> ([8:7-8], (Ref LocalRef {ref_loc = [8:7-8]; index = 5}));
{ "B" -> ([9:7-8], (Ref LocalRef {ref_loc = [9:7-8]; index = 6}));
"bar1" -> ([2:23-27], (Ref LocalRef {ref_loc = [2:23-27]; index = 0}));
"bar2" -> ([3:16-20], (Ref LocalRef {ref_loc = [3:16-20]; index = 1}));
"bar3" -> ([4:14-18], (Ref LocalRef {ref_loc = [4:14-18]; index = 2}));
"f" -> ([5:19-20], (Ref LocalRef {ref_loc = [5:19-20]; index = 3})) };
types = { "Baz" -> ([7:15-18], (Ref LocalRef {ref_loc = [7:15-18]; index = 4})) }}
types =
{ "Baz" -> ([7:15-18], (Ref LocalRef {ref_loc = [7:15-18]; index = 4}));
"Boz" -> ([8:14-17], (Ref LocalRef {ref_loc = [8:14-17]; index = 5})) }}

Builtin global value ns |}]

Expand Down
6 changes: 3 additions & 3 deletions src/typing/errors/error_message.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3182,22 +3182,22 @@ let friendly_message_of_msg loc_of_aloc msg =
| ContextDependentUnsupportedStatement (UnsupportedStatementInLibdef kind) ->
[
text "Cannot use ";
code kind;
text kind;
text " statements in a library file. ";
text "The statement will be ignored.";
]
| ContextDependentUnsupportedStatement (UnsupportedStatementInDeclareModule kind) ->
[
text "Cannot use ";
code kind;
text kind;
text " statements with in ";
code "declare module";
text ". The statement will be ignored.";
]
| ContextDependentUnsupportedStatement (UnsupportedStatementInDeclareNamespace kind) ->
[
text "Cannot use ";
code kind;
text kind;
text " statements with in ";
code "declare namespace";
text ". The statement will be ignored.";
Expand Down
2 changes: 1 addition & 1 deletion src/typing/type_inference_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ class lib_def_loc_mapper_and_validator cx =
| OpaqueType _ ->
None
| ExportNamedDeclaration { ExportNamedDeclaration.export_kind = ExportValue; _ } ->
Some (error "export")
Some (error "value export")
| ImportDeclaration _ ->
if in_toplevel_scope then
Some
Expand Down
Loading

0 comments on commit 518a328

Please sign in to comment.