diff --git a/src/quick-lint-js/fe/lex.cpp b/src/quick-lint-js/fe/lex.cpp index c46825f6ee..72c41b7a93 100644 --- a/src/quick-lint-js/fe/lex.cpp +++ b/src/quick-lint-js/fe/lex.cpp @@ -998,7 +998,13 @@ 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; @@ -1018,6 +1024,7 @@ void Lexer::skip_as_greater() { } this->last_token_.has_leading_newline = false; this->last_token_.begin += 1; + this->last_token_.end = this->input_; this->last_last_token_end_ = this->last_token_.begin; } diff --git a/test/test-parse-typescript-generic.cpp b/test/test-parse-typescript-generic.cpp index 6d07caef12..530c05cf4e 100644 --- a/test/test-parse-typescript-generic.cpp +++ b/test/test-parse-typescript-generic.cpp @@ -1098,6 +1098,64 @@ 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=>{};"_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>=> {};"_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")})); + } + { + Spy_Visitor p = test_parse_and_visit_statement( + u8"class C { method(): C=> {} }"_sv, // + u8" ^^ Diag_Functions_Or_Methods_Should_Not_Have_Arrow_Operator"_diag, + typescript_options); + EXPECT_THAT(p.visits, ElementsAreArray({ + "visit_enter_class_scope", // + "visit_variable_declaration", + "visit_enter_class_scope_body", // + "visit_enter_function_scope", // + "visit_enter_type_scope", // : + "visit_variable_type_use", // T + "visit_variable_type_use", // C + "visit_exit_type_scope", // + "visit_enter_function_scope_body", // + "visit_exit_function_scope", // + "visit_property_declaration", // method + "visit_exit_class_scope", + "visit_variable_declaration", // C + })); + } +} + TEST_F(Test_Parse_TypeScript_Generic, unambiguous_generic_arguments_are_parsed_in_javascript) { {