diff --git a/src/quick-lint-js/fe/parse-class.cpp b/src/quick-lint-js/fe/parse-class.cpp index c28897ed46..5a50145d9d 100644 --- a/src/quick-lint-js/fe/parse-class.cpp +++ b/src/quick-lint-js/fe/parse-class.cpp @@ -1042,7 +1042,7 @@ void Parser::parse_and_visit_class_or_interface_member( } else { p->parse_typescript_colon_for_type(); } - p->parse_and_visit_typescript_type_expression(v); + p->parse_and_visit_typescript_type_expression_no_scope(v); if (p->peek().type == Token_Type::equal) { this->parse_field_initializer(); diff --git a/src/quick-lint-js/fe/parse-expression.cpp b/src/quick-lint-js/fe/parse-expression.cpp index e1b276c063..54c0aa4a1f 100644 --- a/src/quick-lint-js/fe/parse-expression.cpp +++ b/src/quick-lint-js/fe/parse-expression.cpp @@ -2278,7 +2278,7 @@ Expression* Parser::parse_expression_remainder(Parse_Visitor_Base& v, } else { // x as Type // x satisfies Type - this->parse_and_visit_typescript_type_expression( + this->parse_and_visit_typescript_type_expression_no_scope( v, TypeScript_Type_Parse_Options{ // A trailing '?' might be the start of a conditional expression: @@ -4078,7 +4078,7 @@ Expression* Parser::parse_typescript_angle_type_assertion_expression( this->skip(); auto parse_as_type_assertion = [&]() -> Expression* { - this->parse_and_visit_typescript_type_expression(v); + this->parse_and_visit_typescript_type_expression_no_scope(v); QLJS_PARSER_UNIMPLEMENTED_IF_NOT_TOKEN(Token_Type::greater); const Char8* greater_end = this->peek().end; diff --git a/src/quick-lint-js/fe/parse-statement.cpp b/src/quick-lint-js/fe/parse-statement.cpp index 3079febdb3..094831b730 100644 --- a/src/quick-lint-js/fe/parse-statement.cpp +++ b/src/quick-lint-js/fe/parse-statement.cpp @@ -1807,7 +1807,7 @@ void Parser::parse_and_visit_typescript_generic_parameters( }); } this->skip(); - this->parse_and_visit_typescript_type_expression( + this->parse_and_visit_typescript_type_expression_no_scope( extends_visits.visitor(), TypeScript_Type_Parse_Options{ .type_being_declared = @@ -1821,7 +1821,7 @@ void Parser::parse_and_visit_typescript_generic_parameters( if (this->peek().type == Token_Type::equal) { // this->skip(); - this->parse_and_visit_typescript_type_expression(v); + this->parse_and_visit_typescript_type_expression_no_scope(v); } QLJS_ASSERT(parameter_name.has_value()); @@ -3396,7 +3396,7 @@ void Parser::parse_and_visit_typescript_type_alias( } QLJS_PARSER_UNIMPLEMENTED_IF_NOT_TOKEN(Token_Type::equal); this->skip(); - this->parse_and_visit_typescript_type_expression( + this->parse_and_visit_typescript_type_expression_no_scope( v, TypeScript_Type_Parse_Options{ .type_being_declared = TypeScript_Type_Parse_Options::Declaring_Type{ @@ -3844,7 +3844,7 @@ bool Parser::parse_and_visit_catch_or_finally_or_both(Parse_Visitor_Base &v) { default: { const Char8 *type_expression_begin = this->peek().begin; - this->parse_and_visit_typescript_type_expression( + this->parse_and_visit_typescript_type_expression_no_scope( Null_Visitor::instance); const Char8 *type_expression_end = this->lexer_.end_of_previous_token(); diff --git a/src/quick-lint-js/fe/parse-type.cpp b/src/quick-lint-js/fe/parse-type.cpp index d16e0a6947..36c9aba2b3 100644 --- a/src/quick-lint-js/fe/parse-type.cpp +++ b/src/quick-lint-js/fe/parse-type.cpp @@ -44,15 +44,16 @@ void Parser::parse_and_visit_typescript_colon_type_expression( void Parser::parse_and_visit_typescript_colon_type_expression( Parse_Visitor_Base &v, const TypeScript_Type_Parse_Options &parse_options) { this->parse_typescript_colon_for_type(); - this->parse_and_visit_typescript_type_expression(v, parse_options); + this->parse_and_visit_typescript_type_expression_no_scope(v, parse_options); } -void Parser::parse_and_visit_typescript_type_expression(Parse_Visitor_Base &v) { - this->parse_and_visit_typescript_type_expression( +void Parser::parse_and_visit_typescript_type_expression_no_scope( + Parse_Visitor_Base &v) { + this->parse_and_visit_typescript_type_expression_no_scope( v, TypeScript_Type_Parse_Options()); } -void Parser::parse_and_visit_typescript_type_expression( +void Parser::parse_and_visit_typescript_type_expression_no_scope( Parse_Visitor_Base &v, const TypeScript_Type_Parse_Options &parse_options) { Depth_Guard guard(this); TypeScript_Only_Construct_Guard ts_guard = @@ -241,7 +242,7 @@ void Parser::parse_and_visit_typescript_type_expression( .is_keyword = is_keyword, }); } - this->parse_and_visit_typescript_type_expression(v); + this->parse_and_visit_typescript_type_expression_no_scope(v); return; } @@ -433,7 +434,7 @@ void Parser::parse_and_visit_typescript_type_expression( // T extends infer U extends X ? V : W // ^^^^^^^ this->skip(); - this->parse_and_visit_typescript_type_expression( + this->parse_and_visit_typescript_type_expression_no_scope( v, TypeScript_Type_Parse_Options{ .parse_question_as_invalid = false, }); @@ -665,7 +666,7 @@ void Parser::parse_and_visit_typescript_type_expression( } // keyof Type this->lexer_.commit_transaction(std::move(transaction)); - this->parse_and_visit_typescript_type_expression(v, parse_options); + this->parse_and_visit_typescript_type_expression_no_scope(v, parse_options); break; } @@ -737,7 +738,7 @@ void Parser::parse_and_visit_typescript_type_expression( is_array_type = true; this->skip(); } else { - this->parse_and_visit_typescript_type_expression(v); + this->parse_and_visit_typescript_type_expression_no_scope(v); QLJS_PARSER_UNIMPLEMENTED_IF_NOT_TOKEN(Token_Type::right_square); this->skip(); } @@ -778,7 +779,7 @@ void Parser::parse_and_visit_typescript_type_expression( this->fatal_parse_error_stack_.try_finally( [&]() -> void { this->typescript_infer_declaration_buffer_ = &infer_visitor.visitor(); - this->parse_and_visit_typescript_type_expression( + this->parse_and_visit_typescript_type_expression_no_scope( v, TypeScript_Type_Parse_Options{ .type_being_declared = parse_options.type_being_declared, .parse_question_as_invalid = false, @@ -794,7 +795,7 @@ void Parser::parse_and_visit_typescript_type_expression( v.visit_enter_conditional_type_scope(); infer_visitor.visitor().move_into(v); - this->parse_and_visit_typescript_type_expression( + this->parse_and_visit_typescript_type_expression_no_scope( v, TypeScript_Type_Parse_Options{ // See NOTE[TypeScript-extends-cycle]. .type_being_declared = std::nullopt, @@ -803,7 +804,7 @@ void Parser::parse_and_visit_typescript_type_expression( v.visit_exit_conditional_type_scope(); this->skip(); - this->parse_and_visit_typescript_type_expression( + this->parse_and_visit_typescript_type_expression_no_scope( v, TypeScript_Type_Parse_Options{ // See NOTE[TypeScript-extends-cycle]. .type_being_declared = std::nullopt, @@ -841,7 +842,7 @@ void Parser:: this->skip(); QLJS_PARSER_UNIMPLEMENTED_IF_NOT_TOKEN(Token_Type::equal_greater); this->skip(); - this->parse_and_visit_typescript_type_expression( + this->parse_and_visit_typescript_type_expression_no_scope( v, TypeScript_Type_Parse_Options{ // TODO(strager): Report // Diag_TypeScript_Question_In_Type_Expression_Should_Be_Void (i.e. @@ -875,7 +876,7 @@ Parser::parse_and_visit_typescript_arrow_or_paren_type_expression( Stacked_Buffering_Visitor params_visitor = this->buffering_visitor_stack_.push(); const Char8 *old_begin = this->peek().begin; - this->parse_and_visit_typescript_type_expression( + this->parse_and_visit_typescript_type_expression_no_scope( params_visitor.visitor(), TypeScript_Type_Parse_Options{ .type_being_declared = parse_options.type_being_declared, @@ -1078,12 +1079,12 @@ void Parser::parse_and_visit_typescript_object_type_expression( this->skip(); is_index_signature = true; v.visit_enter_index_signature_scope(); - this->parse_and_visit_typescript_type_expression(v); + this->parse_and_visit_typescript_type_expression_no_scope(v); v.visit_variable_declaration(ident, Variable_Kind::_generic_parameter, Variable_Declaration_Flags::none); if (this->peek().type == Token_Type::kw_as) { this->skip(); - this->parse_and_visit_typescript_type_expression(v); + this->parse_and_visit_typescript_type_expression_no_scope(v); } break; @@ -1153,7 +1154,7 @@ void Parser::parse_and_visit_typescript_template_type_expression( QLJS_ASSERT(this->peek().type == Token_Type::incomplete_template); // TODO(strager): report_errors_for_escape_sequences_in_template this->skip(); - this->parse_and_visit_typescript_type_expression(v, parse_options); + this->parse_and_visit_typescript_type_expression_no_scope(v, parse_options); switch (this->peek().type) { case Token_Type::right_curly: this->lexer_.skip_in_template(template_begin); @@ -1239,7 +1240,7 @@ void Parser::parse_and_visit_typescript_tuple_type_expression( .colon = colon_span, }); this->skip(); - this->parse_and_visit_typescript_type_expression( + this->parse_and_visit_typescript_type_expression_no_scope( v, TypeScript_Type_Parse_Options{ .parse_question_as_invalid = false, }); @@ -1329,7 +1330,7 @@ void Parser::parse_and_visit_typescript_tuple_type_expression( this->skip(); } - this->parse_and_visit_typescript_type_expression( + this->parse_and_visit_typescript_type_expression_no_scope( v, TypeScript_Type_Parse_Options{ .parse_question_as_invalid = false, }); @@ -1353,7 +1354,7 @@ void Parser::parse_and_visit_typescript_tuple_type_expression( } first_unnamed_element_begin = this->peek().begin; - this->parse_and_visit_typescript_type_expression( + this->parse_and_visit_typescript_type_expression_no_scope( v, TypeScript_Type_Parse_Options{ .parse_question_as_invalid = false, }); @@ -1364,7 +1365,7 @@ void Parser::parse_and_visit_typescript_tuple_type_expression( // [(Type)] default: first_unnamed_element_begin = this->peek().begin; - this->parse_and_visit_typescript_type_expression( + this->parse_and_visit_typescript_type_expression_no_scope( v, TypeScript_Type_Parse_Options{ .parse_question_as_invalid = false, }); @@ -1452,10 +1453,10 @@ void Parser::parse_and_visit_typescript_generic_arguments( this->skip(); } - this->parse_and_visit_typescript_type_expression(v); + this->parse_and_visit_typescript_type_expression_no_scope(v); while (this->peek().type == Token_Type::comma) { this->skip(); - this->parse_and_visit_typescript_type_expression(v); + this->parse_and_visit_typescript_type_expression_no_scope(v); } switch (this->peek().type) { diff --git a/src/quick-lint-js/fe/parse.h b/src/quick-lint-js/fe/parse.h index 7233a56b00..f84b33f230 100644 --- a/src/quick-lint-js/fe/parse.h +++ b/src/quick-lint-js/fe/parse.h @@ -224,8 +224,11 @@ class Parser { void parse_and_visit_typescript_colon_type_expression(Parse_Visitor_Base &v); void parse_and_visit_typescript_colon_type_expression( Parse_Visitor_Base &v, const TypeScript_Type_Parse_Options &); - void parse_and_visit_typescript_type_expression(Parse_Visitor_Base &v); - void parse_and_visit_typescript_type_expression( + // The _no_scope variant does not emit visit_enter_type_scope or + // visit_exit_type_scope. + void parse_and_visit_typescript_type_expression_no_scope( + Parse_Visitor_Base &v); + void parse_and_visit_typescript_type_expression_no_scope( Parse_Visitor_Base &v, const TypeScript_Type_Parse_Options &); enum class TypeScript_Type_Arrow_Or_Paren { diff --git a/test/quick-lint-js/parse-support.h b/test/quick-lint-js/parse-support.h index 575a461836..1a81cfcd86 100644 --- a/test/quick-lint-js/parse-support.h +++ b/test/quick-lint-js/parse-support.h @@ -122,8 +122,10 @@ class Test_Parser { this->errors_); } + // Does not emit visit_enter_type_scope or visit_exit_type_scope. void parse_and_visit_typescript_type_expression() { - this->parser_.parse_and_visit_typescript_type_expression(this->errors_); + this->parser_.parse_and_visit_typescript_type_expression_no_scope( + this->errors_); } void parse_and_visit_typescript_generic_parameters() { @@ -264,9 +266,12 @@ Spy_Visitor test_parse_and_visit_expression( String8_View input, Span, Parser_Options, Source_Location caller = Source_Location::current()); -// Create a Parser and call Parser::parse_and_visit_typescript_type_expression. -// Assert that exactly the given diagnostics were emitted. See -// NOTE[_diag-syntax] for examples. +// Create a Parser and call +// Parser::parse_and_visit_typescript_type_expression_no_scope. Assert that +// exactly the given diagnostics were emitted. See NOTE[_diag-syntax] for +// examples. +// +// Does not emit visit_enter_type_scope or visit_exit_type_scope. Spy_Visitor test_parse_and_visit_typescript_type_expression( String8_View input, No_Diags_Tag, Parser_Options, Source_Location caller = Source_Location::current());