From 0549ae5b24832ed6d64102a265d0a8b0bb273d75 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): add diagnostic for expected ident after optional chain (#16132) 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/expression.rs | 2 +- tasks/coverage/snapshots/parser_babel.snap | 3 ++- tasks/coverage/snapshots/parser_misc.snap | 12 ++++++++---- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/crates/oxc_parser/src/diagnostics.rs b/crates/oxc_parser/src/diagnostics.rs index b201536d3014d..40fa81f0a59b0 100644 --- a/crates/oxc_parser/src/diagnostics.rs +++ b/crates/oxc_parser/src/diagnostics.rs @@ -1117,3 +1117,10 @@ pub fn unexpected_optional_declaration(span: Span) -> OxcDiagnostic { .with_label(span) .with_help("Remove the `?`") } + +#[cold] +pub fn identifier_expected_after_question_dot(span: Span) -> OxcDiagnostic { + OxcDiagnostic::error("Identifier expected after '?.'") + .with_label(span) + .with_help("Add an identifier after '?.'") +} diff --git a/crates/oxc_parser/src/js/expression.rs b/crates/oxc_parser/src/js/expression.rs index 9d7402e0083ad..750890e49bb2f 100644 --- a/crates/oxc_parser/src/js/expression.rs +++ b/crates/oxc_parser/src/js/expression.rs @@ -987,7 +987,7 @@ impl<'a> ParserImpl<'a> { if let Some(span) = question_dot_span { // We parsed `?.` but then failed to parse anything, so report a missing identifier here. - let error = diagnostics::unexpected_token(span); + let error = diagnostics::identifier_expected_after_question_dot(span); return self.fatal_error(error); } diff --git a/tasks/coverage/snapshots/parser_babel.snap b/tasks/coverage/snapshots/parser_babel.snap index 0b62e4bab6ea4..5a0ff2024a109 100644 --- a/tasks/coverage/snapshots/parser_babel.snap +++ b/tasks/coverage/snapshots/parser_babel.snap @@ -14698,11 +14698,12 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc ╰──── help: Try inserting a semicolon here - × Unexpected token + × Identifier expected after '?.' ╭─[babel/packages/babel-parser/test/fixtures/typescript/type-arguments/call-optional-chain-invalid/input.ts:1:2] 1 │ f?.[1]; · ── ╰──── + help: Add an identifier after '?.' × TS(1099): Type argument list cannot be empty. ╭─[babel/packages/babel-parser/test/fixtures/typescript/type-arguments/empty-function/input.ts:1:4] diff --git a/tasks/coverage/snapshots/parser_misc.snap b/tasks/coverage/snapshots/parser_misc.snap index cb3454226e4dd..096358672c38c 100644 --- a/tasks/coverage/snapshots/parser_misc.snap +++ b/tasks/coverage/snapshots/parser_misc.snap @@ -3532,32 +3532,36 @@ Negative Passed: 120/120 (100.00%) 5 │ } ╰──── - × Unexpected token + × Identifier expected after '?.' ╭─[misc/fail/oxc-9497.js:2:8] 1 │ let repro = {}; 2 │ repro.f?. · ── ╰──── + help: Add an identifier after '?.' - × Unexpected token + × Identifier expected after '?.' ╭─[misc/fail/oxc-9525-1.js:1:2] 1 │ x?.; · ── ╰──── + help: Add an identifier after '?.' - × Unexpected token + × Identifier expected after '?.' ╭─[misc/fail/oxc-9525-2.js:1:3] 1 │ [x?.]; · ── ╰──── + help: Add an identifier after '?.' - × Unexpected token + × Identifier expected after '?.' ╭─[misc/fail/oxc-9525-3.js:2:4] 1 │ () => { 2 │ x?. · ── 3 │ } ╰──── + help: Add an identifier after '?.' × The keyword 'let' is reserved ╭─[misc/fail/oxc.js:3:1]