Skip to content

Commit 43675c2

Browse files
committed
fix(typescript): don't double-diagnose 'break;' inside 'declare namespace'
1 parent 102de78 commit 43675c2

File tree

4 files changed

+30
-9
lines changed

4 files changed

+30
-9
lines changed

src/quick-lint-js/fe/parse-statement.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,6 @@ bool Parser::parse_and_visit_statement(Parse_Visitor_Base &v,
656656
case Token_Type::kw_break:
657657
case Token_Type::kw_continue:
658658
this->is_current_typescript_namespace_non_empty_ = true;
659-
on_non_declaring_statement();
660659
this->parse_and_visit_break_or_continue();
661660
break;
662661

src/quick-lint-js/fe/parse.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -955,24 +955,31 @@ Parser::enter_typescript_namespace_or_module(
955955
this,
956956
std::exchange(this->in_typescript_namespace_or_module_,
957957
namespace_or_module_keyword_span),
958-
std::exchange(this->in_typescript_module_, entering_module));
958+
std::exchange(this->in_typescript_module_, entering_module),
959+
std::exchange(this->in_loop_statement_, false),
960+
std::exchange(this->in_switch_statement_, false));
959961
}
960962

961963
Parser::TypeScript_Namespace_Or_Module_Guard::
962964
TypeScript_Namespace_Or_Module_Guard(
963965
Parser* parser,
964966
std::optional<Source_Code_Span> old_in_typescript_namespace_or_module,
965-
bool old_in_typescript_module)
967+
bool old_in_typescript_module, bool old_in_loop_statement,
968+
bool old_in_switch_statement)
966969
: parser_(parser),
967970
old_in_typescript_namespace_or_module_(
968971
old_in_typescript_namespace_or_module),
969-
old_in_typescript_module_(old_in_typescript_module) {}
972+
old_in_typescript_module_(old_in_typescript_module),
973+
old_in_loop_statement_(old_in_loop_statement),
974+
old_in_switch_statement_(old_in_switch_statement) {}
970975

971976
Parser::TypeScript_Namespace_Or_Module_Guard::
972977
~TypeScript_Namespace_Or_Module_Guard() {
973978
this->parser_->in_typescript_namespace_or_module_ =
974979
this->old_in_typescript_namespace_or_module_;
975980
this->parser_->in_typescript_module_ = this->old_in_typescript_module_;
981+
this->parser_->in_loop_statement_ = this->old_in_loop_statement_;
982+
this->parser_->in_switch_statement_ = this->old_in_switch_statement_;
976983
}
977984

978985
bool Parser::Parse_Expression_Cache_Key::operator==(

src/quick-lint-js/fe/parse.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,8 @@ class Parser {
982982
explicit TypeScript_Namespace_Or_Module_Guard(
983983
Parser *,
984984
std::optional<Source_Code_Span> old_in_typescript_namespace_or_module,
985-
bool old_in_typescript_module);
985+
bool old_in_typescript_module, bool old_in_loop_statement,
986+
bool old_in_switch_statement);
986987

987988
TypeScript_Namespace_Or_Module_Guard(
988989
const TypeScript_Namespace_Or_Module_Guard &) = delete;
@@ -995,6 +996,8 @@ class Parser {
995996
Parser *parser_;
996997
std::optional<Source_Code_Span> old_in_typescript_namespace_or_module_;
997998
bool old_in_typescript_module_;
999+
bool old_in_loop_statement_;
1000+
bool old_in_switch_statement_;
9981001
};
9991002
// Sets in_typescript_namespace_or_module_ and in_typescript_module_.
10001003
[[nodiscard]] TypeScript_Namespace_Or_Module_Guard

test/test-parse-typescript-declare-namespace.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,19 +1012,31 @@ TEST_F(Test_Parse_TypeScript_Declare_Namespace,
10121012
u8" ^^^^^^^^ Diag_Declare_Namespace_Cannot_Contain_Statement.first_statement_token"_diag, //
10131013
u8" ^^^^^^^ Diag_Keywords_Cannot_Contain_Escape_Sequences"_diag,
10141014
typescript_options);
1015+
}
10151016

1016-
// TODO(strager): Perhaps we should only emit
1017-
// Diag_Invalid_Break/Diag_Invalid_Continue.
1017+
TEST_F(
1018+
Test_Parse_TypeScript_Declare_Namespace,
1019+
declare_namespace_does_not_report_double_diagnostic_for_certain_statements) {
10181020
test_parse_and_visit_module(
10191021
u8"declare namespace ns { break; }"_sv, //
1020-
u8" ^^^^^ Diag_Declare_Namespace_Cannot_Contain_Statement.first_statement_token"_diag, //
10211022
u8" ^^^^^ Diag_Invalid_Break"_diag,
10221023
typescript_options);
1024+
test_parse_and_visit_module(
1025+
u8"for (;;) { declare namespace ns { break; } }"_sv, //
1026+
u8" ^^^^^ Diag_Invalid_Break"_diag,
1027+
typescript_options);
1028+
test_parse_and_visit_module(
1029+
u8"switch (true) { default: declare namespace ns { break; } }"_sv, //
1030+
u8" ^^^^^ Diag_Invalid_Break"_diag,
1031+
typescript_options);
10231032
test_parse_and_visit_module(
10241033
u8"declare namespace ns { continue; }"_sv, //
1025-
u8" ^^^^^^^^ Diag_Declare_Namespace_Cannot_Contain_Statement.first_statement_token"_diag, //
10261034
u8" ^^^^^^^^ Diag_Invalid_Continue"_diag,
10271035
typescript_options);
1036+
test_parse_and_visit_module(
1037+
u8"for (;;) { declare namespace ns { continue; } }"_sv, //
1038+
u8" ^^^^^^^^ Diag_Invalid_Continue"_diag,
1039+
typescript_options);
10281040
}
10291041

10301042
TEST_F(Test_Parse_TypeScript_Declare_Namespace,

0 commit comments

Comments
 (0)