From 7ba920f9332f823332efba1b49dc7d959dd95934 Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Mon, 5 Aug 2019 20:45:09 +0500 Subject: [PATCH 1/5] [typing] Add destructuring to catch --- src/typing/statement.ml | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/typing/statement.ml b/src/typing/statement.ml index c281c2199f5..f06ca5e48af 100644 --- a/src/typing/statement.ml +++ b/src/typing/statement.ml @@ -695,8 +695,38 @@ and statement cx : 'a -> (ALoc.t, ALoc.t * Type.t) Ast.Statement.t = Ast.Stateme }, abnormal_opt - - | loc, Identifier _ -> + | ((ploc, Object _) as id) + | ((ploc, Array _) as id) -> + let id_reason = mk_reason RDestructuring ploc in + let annot = Destructuring.type_of_pattern id in + match annot with + | Ast.Type.Available (_, (loc, _)) -> + Flow.add_output cx Error_message.(EUnsupportedSyntax (loc, CatchParameterAnnotation)); + Tast_utils.error_mapper#catch_clause catch_clause, None + | _ -> + let annot_t, _ = Anno.mk_type_annotation cx SMap.empty id_reason annot in + let init = Destructuring.empty annot_t ~annot:false in + let (stmts, abnormal_opt), id_ast = Env.in_lex_scope cx (fun () -> + let id_ast = Destructuring.pattern cx ~expr:expression init id ~f:(fun ~use_op loc name default t -> + let reason = mk_reason (RIdentifier name) loc in + Scope.(Env.bind_implicit_let ~state:State.Initialized Entry.CatchParamBinding cx name t loc); + (* Env.declare_let cx name loc; *) + (* Env.init_let cx ~use_op name ~has_anno:false t loc; *) + Flow.flow cx (t, AssertImportIsValueT (reason, name)); + Option.iter default ~f:(fun d -> + let default_t = Flow.mk_default cx reason d in + Flow.flow cx (default_t, UseT (use_op, t)) + ) + ) in + check cx b, id_ast + ) in + { Try.CatchClause. + param = Some id_ast; + body = b_loc, { Block.body = stmts }; + }, + abnormal_opt + + | _, Identifier { Identifier.annot = Ast.Type.Available (_, (loc, _)); _ } -> Flow.add_output cx Error_message.(EUnsupportedSyntax (loc, CatchParameterAnnotation)); Tast_utils.error_mapper#catch_clause catch_clause, None From 20178a93a9188e43d96a8e1cf8b5ce5420d4201f Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Mon, 5 Aug 2019 20:54:27 +0500 Subject: [PATCH 2/5] [tests] Add catch destructuring tests --- tests/try/destructuring-catch.js | 34 ++++++++++++++++++ tests/try/try.diff | 62 ++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 tests/try/destructuring-catch.js create mode 100644 tests/try/try.diff diff --git a/tests/try/destructuring-catch.js b/tests/try/destructuring-catch.js new file mode 100644 index 00000000000..ef659c1a8b6 --- /dev/null +++ b/tests/try/destructuring-catch.js @@ -0,0 +1,34 @@ +/*** + * @flow + */ + +// object destructuring +function f() { + try { + + } catch ({message}) { + message // ok + const foo: string = 1; // it typechecks + } +} + +// array destructuring +function f() { + try { + + } catch ([bar, baz]) { + bar // ok + baz // ok + const foo: string = 1; // it typechecks + } +} + +// type annotation is banned +function f() { + try { + + } catch ({message}: any) { + message // ok + const foo: string = 1; // it typechecks + } +} diff --git a/tests/try/try.diff b/tests/try/try.diff new file mode 100644 index 00000000000..e616159b430 --- /dev/null +++ b/tests/try/try.diff @@ -0,0 +1,62 @@ +--- try.exp ++++ try.out +@@ -1,3 +1,53 @@ ++Error ------------------------------------------------------------------------------------- destructuring-catch.js:11:25 ++ ++Cannot assign `1` to `foo` because number [1] is incompatible with string [2]. ++ ++ destructuring-catch.js:11:25 ++ 11| const foo: string = 1; // it typechecks ++ ^ [1] ++ ++References: ++ destructuring-catch.js:11:16 ++ 11| const foo: string = 1; // it typechecks ++ ^^^^^^ [2] ++ ++ ++Error ------------------------------------------------------------------------------------- destructuring-catch.js:22:25 ++ ++Cannot assign `1` to `foo` because number [1] is incompatible with string [2]. ++ ++ destructuring-catch.js:22:25 ++ 22| const foo: string = 1; // it typechecks ++ ^ [1] ++ ++References: ++ destructuring-catch.js:22:16 ++ 22| const foo: string = 1; // it typechecks ++ ^^^^^^ [2] ++ ++ ++Error ------------------------------------------------------------------------------------- destructuring-catch.js:30:23 ++ ++Type annotations for catch parameters are not yet supported. ++ ++ 30| } catch ({message}: any) { ++ ^^^ ++ ++ ++Error ------------------------------------------------------------------------------------- destructuring-catch.js:32:25 ++ ++Cannot assign `1` to `foo` because number [1] is incompatible with string [2]. ++ ++ destructuring-catch.js:32:25 ++ 32| const foo: string = 1; // it typechecks ++ ^ [1] ++ ++References: ++ destructuring-catch.js:32:16 ++ 32| const foo: string = 1; // it typechecks ++ ^^^^^^ [2] ++ ++ + Error ---------------------------------------------------------------------------------------------------- init.js:34:20 + + Cannot assign `x` to `y` because possibly uninitialized variable [1] is incompatible with number [2]. +@@ -338,4 +388,4 @@ + + + +-Found 22 errors ++Found 26 errors From cc98b85a2750dbe2918b432cb7267810df7ad00d Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Mon, 5 Aug 2019 21:00:44 +0500 Subject: [PATCH 3/5] [tests] Add annotation location tests --- tests/try/test.js | 9 +++++++ tests/try/try.diff | 62 ---------------------------------------------- tests/try/try.exp | 60 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 68 insertions(+), 63 deletions(-) delete mode 100644 tests/try/try.diff diff --git a/tests/try/test.js b/tests/try/test.js index 2e313d09fb3..e18a7254be3 100644 --- a/tests/try/test.js +++ b/tests/try/test.js @@ -71,3 +71,12 @@ function maz() { } var c: string = x[0]; // reachable } + +// type annotation is banned +function maz() { + try { + } catch (e: any) { + e; + var c: string = 1; // it typechecks + } +} diff --git a/tests/try/try.diff b/tests/try/try.diff deleted file mode 100644 index e616159b430..00000000000 --- a/tests/try/try.diff +++ /dev/null @@ -1,62 +0,0 @@ ---- try.exp -+++ try.out -@@ -1,3 +1,53 @@ -+Error ------------------------------------------------------------------------------------- destructuring-catch.js:11:25 -+ -+Cannot assign `1` to `foo` because number [1] is incompatible with string [2]. -+ -+ destructuring-catch.js:11:25 -+ 11| const foo: string = 1; // it typechecks -+ ^ [1] -+ -+References: -+ destructuring-catch.js:11:16 -+ 11| const foo: string = 1; // it typechecks -+ ^^^^^^ [2] -+ -+ -+Error ------------------------------------------------------------------------------------- destructuring-catch.js:22:25 -+ -+Cannot assign `1` to `foo` because number [1] is incompatible with string [2]. -+ -+ destructuring-catch.js:22:25 -+ 22| const foo: string = 1; // it typechecks -+ ^ [1] -+ -+References: -+ destructuring-catch.js:22:16 -+ 22| const foo: string = 1; // it typechecks -+ ^^^^^^ [2] -+ -+ -+Error ------------------------------------------------------------------------------------- destructuring-catch.js:30:23 -+ -+Type annotations for catch parameters are not yet supported. -+ -+ 30| } catch ({message}: any) { -+ ^^^ -+ -+ -+Error ------------------------------------------------------------------------------------- destructuring-catch.js:32:25 -+ -+Cannot assign `1` to `foo` because number [1] is incompatible with string [2]. -+ -+ destructuring-catch.js:32:25 -+ 32| const foo: string = 1; // it typechecks -+ ^ [1] -+ -+References: -+ destructuring-catch.js:32:16 -+ 32| const foo: string = 1; // it typechecks -+ ^^^^^^ [2] -+ -+ - Error ---------------------------------------------------------------------------------------------------- init.js:34:20 - - Cannot assign `x` to `y` because possibly uninitialized variable [1] is incompatible with number [2]. -@@ -338,4 +388,4 @@ - - - --Found 22 errors -+Found 26 errors diff --git a/tests/try/try.exp b/tests/try/try.exp index 2eb41bd78eb..b9530005ee9 100644 --- a/tests/try/try.exp +++ b/tests/try/try.exp @@ -1,3 +1,53 @@ +Error ------------------------------------------------------------------------------------- destructuring-catch.js:11:25 + +Cannot assign `1` to `foo` because number [1] is incompatible with string [2]. + + destructuring-catch.js:11:25 + 11| const foo: string = 1; // it typechecks + ^ [1] + +References: + destructuring-catch.js:11:16 + 11| const foo: string = 1; // it typechecks + ^^^^^^ [2] + + +Error ------------------------------------------------------------------------------------- destructuring-catch.js:22:25 + +Cannot assign `1` to `foo` because number [1] is incompatible with string [2]. + + destructuring-catch.js:22:25 + 22| const foo: string = 1; // it typechecks + ^ [1] + +References: + destructuring-catch.js:22:16 + 22| const foo: string = 1; // it typechecks + ^^^^^^ [2] + + +Error ------------------------------------------------------------------------------------- destructuring-catch.js:30:23 + +Type annotations for catch parameters are not yet supported. + + 30| } catch ({message}: any) { + ^^^ + + +Error ------------------------------------------------------------------------------------- destructuring-catch.js:32:25 + +Cannot assign `1` to `foo` because number [1] is incompatible with string [2]. + + destructuring-catch.js:32:25 + 32| const foo: string = 1; // it typechecks + ^ [1] + +References: + destructuring-catch.js:32:16 + 32| const foo: string = 1; // it typechecks + ^^^^^^ [2] + + Error ---------------------------------------------------------------------------------------------------- init.js:34:20 Cannot assign `x` to `y` because possibly uninitialized variable [1] is incompatible with number [2]. @@ -337,5 +387,13 @@ References: ^^^^^^ [2] +Error ---------------------------------------------------------------------------------------------------- test.js:78:15 + +Type annotations for catch parameters are not yet supported. + + 78| } catch (e: any) { + ^^^ + + -Found 22 errors +Found 27 errors From f98bd6fa5e81c7ad1c749044d9140fe95d3f137f Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Mon, 5 Aug 2019 22:44:58 +0500 Subject: [PATCH 4/5] [typing] Typecheck catch blocks with annotation --- src/typing/statement.ml | 60 ++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/typing/statement.ml b/src/typing/statement.ml index f06ca5e48af..30a1d49c33f 100644 --- a/src/typing/statement.ml +++ b/src/typing/statement.ml @@ -672,9 +672,15 @@ and statement cx : 'a -> (ALoc.t, ALoc.t * Type.t) Ast.Statement.t = Ast.Stateme | Some p -> (match p with | loc, Identifier { Identifier.name = name_loc, ({ Ast.Identifier.name; comments= _ } as id); - annot = Ast.Type.Missing mloc; + annot; optional; } -> + let mloc = match annot with + | Ast.Type.Missing mloc -> mloc + | Ast.Type.Available (mloc, (loc, _)) -> + Flow.add_output cx Error_message.(EUnsupportedSyntax (loc, CatchParameterAnnotation)); + mloc + in let r = mk_reason (RCustom "catch") loc in let t = Tvar.mk cx r in @@ -699,37 +705,31 @@ and statement cx : 'a -> (ALoc.t, ALoc.t * Type.t) Ast.Statement.t = Ast.Stateme | ((ploc, Array _) as id) -> let id_reason = mk_reason RDestructuring ploc in let annot = Destructuring.type_of_pattern id in - match annot with - | Ast.Type.Available (_, (loc, _)) -> + let annot = match annot with + | Ast.Type.Available (mloc, (loc, _)) -> Flow.add_output cx Error_message.(EUnsupportedSyntax (loc, CatchParameterAnnotation)); - Tast_utils.error_mapper#catch_clause catch_clause, None - | _ -> - let annot_t, _ = Anno.mk_type_annotation cx SMap.empty id_reason annot in - let init = Destructuring.empty annot_t ~annot:false in - let (stmts, abnormal_opt), id_ast = Env.in_lex_scope cx (fun () -> - let id_ast = Destructuring.pattern cx ~expr:expression init id ~f:(fun ~use_op loc name default t -> - let reason = mk_reason (RIdentifier name) loc in - Scope.(Env.bind_implicit_let ~state:State.Initialized Entry.CatchParamBinding cx name t loc); - (* Env.declare_let cx name loc; *) - (* Env.init_let cx ~use_op name ~has_anno:false t loc; *) - Flow.flow cx (t, AssertImportIsValueT (reason, name)); - Option.iter default ~f:(fun d -> - let default_t = Flow.mk_default cx reason d in - Flow.flow cx (default_t, UseT (use_op, t)) - ) - ) in - check cx b, id_ast + Ast.Type.Missing mloc + | _ -> annot + in + let annot_t, _ = Anno.mk_type_annotation cx SMap.empty id_reason annot in + let init = Destructuring.empty annot_t ~annot:false in + let (stmts, abnormal_opt), id_ast = Env.in_lex_scope cx (fun () -> + let id_ast = Destructuring.pattern cx ~expr:expression init id ~f:(fun ~use_op loc name default t -> + let reason = mk_reason (RIdentifier name) loc in + Scope.(Env.bind_implicit_let ~state:State.Initialized Entry.CatchParamBinding cx name t loc); + Flow.flow cx (t, AssertImportIsValueT (reason, name)); + Option.iter default ~f:(fun d -> + let default_t = Flow.mk_default cx reason d in + Flow.flow cx (default_t, UseT (use_op, t)) + ) ) in - { Try.CatchClause. - param = Some id_ast; - body = b_loc, { Block.body = stmts }; - }, - abnormal_opt - - | _, Identifier { Identifier.annot = Ast.Type.Available (_, (loc, _)); _ } -> - Flow.add_output cx - Error_message.(EUnsupportedSyntax (loc, CatchParameterAnnotation)); - Tast_utils.error_mapper#catch_clause catch_clause, None + check cx b, id_ast + ) in + { Try.CatchClause. + param = Some id_ast; + body = b_loc, { Block.body = stmts }; + }, + abnormal_opt | loc, _ -> Flow.add_output cx From 3d9aca4e0b9716e763d72c14e81443f7fde4da8d Mon Sep 17 00:00:00 2001 From: andretshurotshka Date: Mon, 5 Aug 2019 22:47:04 +0500 Subject: [PATCH 5/5] [tests] Add tests for catch annotations --- tests/try/destructuring-catch.js | 10 ++++++++ tests/try/test.js | 4 +-- tests/try/try.exp | 42 +++++++++++++++++++++++++++++--- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/tests/try/destructuring-catch.js b/tests/try/destructuring-catch.js index ef659c1a8b6..b6888f14ab1 100644 --- a/tests/try/destructuring-catch.js +++ b/tests/try/destructuring-catch.js @@ -32,3 +32,13 @@ function f() { const foo: string = 1; // it typechecks } } + +// type annotation doesn't affect type +function f() { + try { + + } catch ({message}: {message: string}) { // error + ;(message: number) // ok + const foo: string = 1; // it typechecks + } +} diff --git a/tests/try/test.js b/tests/try/test.js index e18a7254be3..33222b8f161 100644 --- a/tests/try/test.js +++ b/tests/try/test.js @@ -75,8 +75,8 @@ function maz() { // type annotation is banned function maz() { try { - } catch (e: any) { - e; + } catch (e: string) { // error + (e: number); // ok var c: string = 1; // it typechecks } } diff --git a/tests/try/try.exp b/tests/try/try.exp index b9530005ee9..fd07d6bce30 100644 --- a/tests/try/try.exp +++ b/tests/try/try.exp @@ -48,6 +48,28 @@ References: ^^^^^^ [2] +Error ------------------------------------------------------------------------------------- destructuring-catch.js:40:23 + +Type annotations for catch parameters are not yet supported. + + 40| } catch ({message}: {message: string}) { // error + ^^^^^^^^^^^^^^^^^ + + +Error ------------------------------------------------------------------------------------- destructuring-catch.js:42:25 + +Cannot assign `1` to `foo` because number [1] is incompatible with string [2]. + + destructuring-catch.js:42:25 + 42| const foo: string = 1; // it typechecks + ^ [1] + +References: + destructuring-catch.js:42:16 + 42| const foo: string = 1; // it typechecks + ^^^^^^ [2] + + Error ---------------------------------------------------------------------------------------------------- init.js:34:20 Cannot assign `x` to `y` because possibly uninitialized variable [1] is incompatible with number [2]. @@ -391,9 +413,23 @@ Error -------------------------------------------------------------------------- Type annotations for catch parameters are not yet supported. - 78| } catch (e: any) { - ^^^ + 78| } catch (e: string) { // error + ^^^^^^ + + +Error ---------------------------------------------------------------------------------------------------- test.js:80:21 + +Cannot assign `1` to `c` because number [1] is incompatible with string [2]. + + test.js:80:21 + 80| var c: string = 1; // it typechecks + ^ [1] + +References: + test.js:80:12 + 80| var c: string = 1; // it typechecks + ^^^^^^ [2] -Found 27 errors +Found 30 errors