From db839ae2c27bf419d8386b6d38c56a818468019b Mon Sep 17 00:00:00 2001 From: camchenry <1514176+camchenry@users.noreply.github.com> Date: Wed, 26 Nov 2025 04:32:59 +0000 Subject: [PATCH] feat(parser): improve diagnostic for unexpected optional declarations (#16131) Currently we just emit "unexpected token", but we actually have a good amount of context here to provide better help + error message. --- crates/oxc_parser/src/diagnostics.rs | 7 +++++++ crates/oxc_parser/src/js/declaration.rs | 2 +- tasks/coverage/snapshots/parser_misc.snap | 21 ++++++++++++++------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/crates/oxc_parser/src/diagnostics.rs b/crates/oxc_parser/src/diagnostics.rs index a769f3fb52904..b201536d3014d 100644 --- a/crates/oxc_parser/src/diagnostics.rs +++ b/crates/oxc_parser/src/diagnostics.rs @@ -1110,3 +1110,10 @@ pub fn expect_switch_clause(span: Span) -> OxcDiagnostic { .with_label(span.label("`case` or `default` clause expected here")) .with_help("If this is intended to be the condition for the switch statement, add `case` before it.") } + +#[cold] +pub fn unexpected_optional_declaration(span: Span) -> OxcDiagnostic { + OxcDiagnostic::error("Optional declaration is not allowed here") + .with_label(span) + .with_help("Remove the `?`") +} diff --git a/crates/oxc_parser/src/js/declaration.rs b/crates/oxc_parser/src/js/declaration.rs index a06c140503c35..442e4e74bddf1 100644 --- a/crates/oxc_parser/src/js/declaration.rs +++ b/crates/oxc_parser/src/js/declaration.rs @@ -118,7 +118,7 @@ impl<'a> ParserImpl<'a> { None }; let optional = if self.at(Kind::Question) { - self.error(diagnostics::unexpected_token(self.cur_token().span())); + self.error(diagnostics::unexpected_optional_declaration(self.cur_token().span())); self.bump_any(); true } else { diff --git a/tasks/coverage/snapshots/parser_misc.snap b/tasks/coverage/snapshots/parser_misc.snap index 6ed6a4facc358..cb3454226e4dd 100644 --- a/tasks/coverage/snapshots/parser_misc.snap +++ b/tasks/coverage/snapshots/parser_misc.snap @@ -3273,51 +3273,57 @@ Negative Passed: 120/120 (100.00%) · ───── ╰──── - × Unexpected token + × Optional declaration is not allowed here ╭─[misc/fail/oxc-2253.ts:1:8] 1 │ const a? = "A" · ─ 2 │ const [b]? = ["B"] ╰──── + help: Remove the `?` - × Unexpected token + × Optional declaration is not allowed here ╭─[misc/fail/oxc-2253.ts:2:10] 1 │ const a? = "A" 2 │ const [b]? = ["B"] · ─ 3 │ const { c }? = { c: "C" } ╰──── + help: Remove the `?` - × Unexpected token + × Optional declaration is not allowed here ╭─[misc/fail/oxc-2253.ts:3:12] 2 │ const [b]? = ["B"] 3 │ const { c }? = { c: "C" } · ─ 4 │ ╰──── + help: Remove the `?` - × Unexpected token + × Optional declaration is not allowed here ╭─[misc/fail/oxc-2253.ts:5:13] 4 │ 5 │ const d ? = "A" · ─ 6 │ const [e, f] ? = ["B"] ╰──── + help: Remove the `?` - × Unexpected token + × Optional declaration is not allowed here ╭─[misc/fail/oxc-2253.ts:6:19] 5 │ const d ? = "A" 6 │ const [e, f] ? = ["B"] · ─ 7 │ const { g, h } ? = { c: "C" } ╰──── + help: Remove the `?` - × Unexpected token + × Optional declaration is not allowed here ╭─[misc/fail/oxc-2253.ts:7:22] 6 │ const [e, f] ? = ["B"] 7 │ const { g, h } ? = { c: "C" } · ─ ╰──── + help: Remove the `?` × Empty parenthesized expression ╭─[misc/fail/oxc-232.js:1:5] @@ -3494,12 +3500,13 @@ Negative Passed: 120/120 (100.00%) · ─────── ╰──── - × Unexpected token + × Optional declaration is not allowed here ╭─[misc/fail/oxc-5955-1.ts:1:8] 1 │ const x?: number = 1; · ─ 2 │ ╰──── + help: Remove the `?` × Unexpected token ╭─[misc/fail/oxc-5955-2.ts:3:8]