From e076dd577e4b899ccfb766821ae3d256b269d14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20=F0=9F=91=A8=F0=9F=8F=BD=E2=80=8D=F0=9F=92=BB=20Copl?= =?UTF-8?q?an?= Date: Sun, 7 Jan 2024 16:17:14 -0800 Subject: [PATCH] fix(lex): parse `let f = (): RT=>null;` Test Plan: `let f = (): RT=>null;` Fixes #1169 --- src/quick-lint-js/fe/lex.cpp | 7 ++- test/test-parse-typescript-generic.cpp | 69 ++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/quick-lint-js/fe/lex.cpp b/src/quick-lint-js/fe/lex.cpp index 565f1e6e02..cd1cb44b64 100644 --- a/src/quick-lint-js/fe/lex.cpp +++ b/src/quick-lint-js/fe/lex.cpp @@ -996,7 +996,12 @@ void Lexer::skip_less_less_as_less() { void Lexer::skip_as_greater() { switch (this->last_token_.type) { case Token_Type::greater_equal: - this->last_token_.type = Token_Type::equal; + if (this->input_[0] == '>') { + this->last_token_.type = Token_Type::equal_greater; + this->input_ += 1; + } else { + this->last_token_.type = Token_Type::equal; + } break; case Token_Type::greater_greater_equal: this->last_token_.type = Token_Type::greater_equal; diff --git a/test/test-parse-typescript-generic.cpp b/test/test-parse-typescript-generic.cpp index 6d07caef12..4739d7e706 100644 --- a/test/test-parse-typescript-generic.cpp +++ b/test/test-parse-typescript-generic.cpp @@ -1098,6 +1098,75 @@ TEST_F( } } +TEST_F(Test_Parse_TypeScript_Generic, + greater_equal_greater_is_split_into_two_tokens) { + { + Spy_Visitor p = test_parse_and_visit_statement( + u8"let f = (): RT => null;"_sv, no_diags, typescript_options); + EXPECT_THAT(p.visits, ElementsAreArray({ + "visit_enter_function_scope", // + "visit_enter_type_scope", // : + "visit_variable_type_use", // RT + "visit_variable_type_use", // T + "visit_exit_type_scope", // + "visit_enter_function_scope_body", // { + "visit_exit_function_scope", // } + "visit_variable_declaration", // let f + })); + EXPECT_THAT(p.variable_declarations, + ElementsAreArray({let_init_decl(u8"f")})); + } + { + Spy_Visitor p = test_parse_and_visit_statement( + u8"let f = (): RT=>null;"_sv, no_diags, typescript_options); + EXPECT_THAT(p.visits, ElementsAreArray({ + "visit_enter_function_scope", // + "visit_enter_type_scope", // : + "visit_variable_type_use", // RT + "visit_variable_type_use", // T + "visit_exit_type_scope", // + "visit_enter_function_scope_body", // { + "visit_exit_function_scope", // } + "visit_variable_declaration", // let f + })); + EXPECT_THAT(p.variable_declarations, + ElementsAreArray({let_init_decl(u8"f")})); + } + { + Spy_Visitor p = test_parse_and_visit_statement( + u8"let f = (): RT=> null;"_sv, no_diags, typescript_options); + EXPECT_THAT(p.visits, ElementsAreArray({ + "visit_enter_function_scope", // + "visit_enter_type_scope", // : + "visit_variable_type_use", // RT + "visit_variable_type_use", // T + "visit_exit_type_scope", // + "visit_enter_function_scope_body", // { + "visit_exit_function_scope", // } + "visit_variable_declaration", // let f + })); + EXPECT_THAT(p.variable_declarations, + ElementsAreArray({let_init_decl(u8"f")})); + } + { + Spy_Visitor p = test_parse_and_visit_statement( + u8"let f = (): RT>=> null;"_sv, no_diags, typescript_options); + EXPECT_THAT(p.visits, ElementsAreArray({ + "visit_enter_function_scope", // + "visit_enter_type_scope", // : + "visit_variable_type_use", // RT + "visit_variable_type_use", // RT + "visit_variable_type_use", // T + "visit_exit_type_scope", // + "visit_enter_function_scope_body", // { + "visit_exit_function_scope", // } + "visit_variable_declaration", // let f + })); + EXPECT_THAT(p.variable_declarations, + ElementsAreArray({let_init_decl(u8"f")})); + } +} + TEST_F(Test_Parse_TypeScript_Generic, unambiguous_generic_arguments_are_parsed_in_javascript) { {