Skip to content

Commit 95550fb

Browse files
committed
feat(parser): improve error message for missing conditional alternative
1 parent dedfa97 commit 95550fb

File tree

7 files changed

+43
-3
lines changed

7 files changed

+43
-3
lines changed

crates/oxc_parser/src/cursor.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,20 @@ impl<'a> ParserImpl<'a> {
189189
self.advance(kind);
190190
}
191191

192+
#[inline]
193+
pub(crate) fn expect_conditional_alternative(&mut self, question_span: Span) {
194+
if !self.at(Kind::Colon) {
195+
let range = self.cur_token().span();
196+
let error = diagnostics::expect_conditional_alternative(
197+
self.cur_kind().to_str(),
198+
range,
199+
question_span,
200+
);
201+
self.set_fatal_error(error);
202+
}
203+
self.bump_any(); // bump `:`
204+
}
205+
192206
/// Expect the next next token to be a `JsxChild`, i.e. `<` or `{` or `JSXText`
193207
/// # Errors
194208
pub(crate) fn expect_jsx_child(&mut self, kind: Kind) {

crates/oxc_parser/src/diagnostics.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ pub fn expect_token(x0: &str, x1: &str, span: Span) -> OxcDiagnostic {
4444
.with_label(span.label(format!("`{x0}` expected")))
4545
}
4646

47+
#[cold]
48+
pub fn expect_conditional_alternative(x: &str, span: Span, question_span: Span) -> OxcDiagnostic {
49+
OxcDiagnostic::error(format!("Expected `:` but found `{x}`")).with_labels([
50+
span.primary_label("`:` expected"),
51+
question_span.label("Conditional starts here"),
52+
])
53+
}
54+
4755
#[cold]
4856
pub fn unexpected_trailing_comma(name: &'static str, span: Span) -> OxcDiagnostic {
4957
OxcDiagnostic::error(format!("{name} may not have a trailing comma."))

crates/oxc_parser/src/js/expression.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,7 @@ impl<'a> ParserImpl<'a> {
12161216
lhs: Expression<'a>,
12171217
allow_return_type_in_arrow_function: bool,
12181218
) -> Expression<'a> {
1219+
let question_span = self.token.span();
12191220
if !self.eat(Kind::Question) {
12201221
return lhs;
12211222
}
@@ -1224,7 +1225,7 @@ impl<'a> ParserImpl<'a> {
12241225
/* allow_return_type_in_arrow_function */ false,
12251226
)
12261227
});
1227-
self.expect(Kind::Colon);
1228+
self.expect_conditional_alternative(question_span);
12281229
let alternate =
12291230
self.parse_assignment_expression_or_higher_impl(allow_return_type_in_arrow_function);
12301231
self.ast.expression_conditional(self.end_span(lhs_span), lhs, consequent, alternate)

crates/oxc_parser/src/ts/types.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ impl<'a> ParserImpl<'a> {
2424
{
2525
let extends_type =
2626
self.context_add(Context::DisallowConditionalTypes, Self::parse_ts_type);
27+
let question_span = self.token.span();
2728
self.expect(Kind::Question);
2829
let true_type =
2930
self.context_remove(Context::DisallowConditionalTypes, Self::parse_ts_type);
30-
self.expect(Kind::Colon);
31+
self.expect_conditional_alternative(question_span);
3132
let false_type =
3233
self.context_remove(Context::DisallowConditionalTypes, Self::parse_ts_type);
3334
return self.ast.ts_type_conditional_type(
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
type A = 1 extends 2 ? 3
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
const foo = 1 ? 2

tasks/coverage/snapshots/parser_misc.snap

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
parser_misc Summary:
22
AST Parsed : 48/48 (100.00%)
33
Positive Passed: 48/48 (100.00%)
4-
Negative Passed: 94/94 (100.00%)
4+
Negative Passed: 96/96 (100.00%)
55

66
× Cannot assign to 'arguments' in strict mode
77
╭─[misc/fail/arguments-eval.ts:1:10]
@@ -50,6 +50,20 @@ Negative Passed: 94/94 (100.00%)
5050
8
5151
╰────
5252

53+
× Expected `:` but found `EOF`
54+
╭─[misc/fail/missing-conditional-alternative-type.ts:2:1]
55+
1type A = 1 extends 2 ? 3
56+
· ┬
57+
· ╰── Conditional starts here
58+
╰────
59+
60+
× Expected `:` but found `EOF`
61+
╭─[misc/fail/missing-conditional-alternative.js:2:1]
62+
1const foo = 1 ? 2
63+
· ┬
64+
· ╰── Conditional starts here
65+
╰────
66+
5367
× Identifier `b` has already been declared
5468
╭─[misc/fail/oxc-10159.js:1:22]
5569
1function a() { class b { }; function b() { } }

0 commit comments

Comments
 (0)