Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(es/parser): Make error message helpful #6535

Merged
merged 17 commits into from Nov 29, 2022
20 changes: 16 additions & 4 deletions crates/swc_ecma_parser/src/error.rs
Expand Up @@ -272,6 +272,12 @@ pub enum SyntaxError {
TS4112,
TSTypeAnnotationAfterAssign,
TsNonNullAssertionNotAllowed(JsWord),

WithLabel {
inner: Box<Error>,
span: Span,
note: &'static str,
},
}

impl SyntaxError {
Expand Down Expand Up @@ -698,6 +704,7 @@ impl SyntaxError {
};
format!("Unexpected token. Did you mean {}?", did_you_mean).into()
}
SyntaxError::WithLabel { inner, .. } => inner.error.1.msg(),
}
}
}
Expand All @@ -706,23 +713,28 @@ impl Error {
#[cold]
#[inline(never)]
pub fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder {
if let SyntaxError::WithLabel { inner, note, span } = self.error.1 {
let mut db = inner.into_diagnostic(handler);
db.span_label(span, note);
return db;
}

let span = self.span();

let kind = self.into_kind();
let msg = kind.msg();

let mut db = handler.struct_err(&msg);
db.set_span(span);
let mut db = handler.struct_span_err(span, &msg);

match kind {
SyntaxError::ExpectedSemiForExprStmt { expr } => {
db.span_note(
db.span_label(
expr,
"This is the expression part of an expression statement",
);
}
SyntaxError::MultipleDefault { previous } => {
db.span_note(previous, "previous default case is declared at here");
db.span_label(previous, "previous default case is declared at here");
}
_ => {}
}
Expand Down
33 changes: 25 additions & 8 deletions crates/swc_ecma_parser/src/parser/expr.rs
Expand Up @@ -495,12 +495,7 @@ impl<I: Tokens> Parser<I> {
})));
}

unexpected!(
self,
"this, import, async, function, [ for array literal, { for object literal, @ for \
decorator, function, class, null, true, false, number, bigint, string, regexp, ` for \
template literal, (, or an identifier"
)
syntax_error!(self, self.input.cur_span(), SyntaxError::TS1109)
}

#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
Expand Down Expand Up @@ -751,9 +746,20 @@ impl<I: Tokens> Parser<I> {
let start = cur_pos!(self);

if eat!(self, "...") {
let spread = Some(span!(self, start));
let spread_span = span!(self, start);
let spread = Some(spread_span);
self.include_in_expr(true)
.parse_assignment_expr()
.map_err(|err| {
Error::new(
err.span(),
SyntaxError::WithLabel {
inner: Box::new(err),
span: spread_span,
note: "An expression should follow '...'",
},
)
})
.map(|expr| ExprOrSpread { spread, expr })
} else {
self.parse_assignment_expr()
Expand Down Expand Up @@ -1911,7 +1917,18 @@ impl<I: Tokens> Parser<I> {
})))
} else {
let has_star = eat!(self, '*');
let arg = self.parse_assignment_expr()?;
let err_span = span!(self, start);

let arg = self.parse_assignment_expr().map_err(|err| {
Error::new(
err.span(),
SyntaxError::WithLabel {
inner: Box::new(err),
span: err_span,
note: "Tried to parse an argument of yield",
},
)
})?;

Ok(Box::new(Expr::Yield(YieldExpr {
span: span!(self, start),
Expand Down
16 changes: 15 additions & 1 deletion crates/swc_ecma_parser/src/parser/stmt.rs
Expand Up @@ -449,13 +449,27 @@ impl<'a, I: Tokens> Parser<I> {
let start = cur_pos!(self);

assert_and_bump!(self, "if");
let if_token = self.input.prev_span();

expect!(self, '(');
let ctx = Context {
ignore_else_clause: false,
..self.ctx()
};
let test = self.with_ctx(ctx).include_in_expr(true).parse_expr()?;
let test = self
.with_ctx(ctx)
.include_in_expr(true)
.parse_expr()
.map_err(|err| {
Error::new(
err.span(),
SyntaxError::WithLabel {
inner: Box::new(err),
span: if_token,
note: "Tried to parse the condition for an if statement",
},
)
})?;
if !eat!(self, ')') {
self.emit_err(self.input.cur_span(), SyntaxError::TS1005);

Expand Down
@@ -1,14 +1,8 @@

x Expected ';', '}' or <eof>
,-[$DIR/tests/errors/async-line-break/1/input.js:1:1]
1 | foo = async
2 | () => 42
: ^^
`----

Error:
> This is the expression part of an expression statement
,-[$DIR/tests/errors/async-line-break/1/input.js:1:1]
1 | ,-> foo = async
2 | `-> () => 42
2 | |-> () => 42
: `--- ^^
: `---- This is the expression part of an expression statement
`----
@@ -1,6 +1,5 @@

x Unexpected token `public`. Expected this, import, async, function, [ for array literal, { for object literal, @ for decorator, function, class, null, true, false, number, bigint, string, regexp,
| ` for template literal, (, or an identifier
x Expression expected
,-[$DIR/tests/errors/conflict_marker_trivia_2/input.ts:8:1]
8 | }
9 | ,-> >>>>>>> A
Expand Down
@@ -1,6 +1,5 @@

x Unexpected token `> (jsx tag end)`. Expected this, import, async, function, [ for array literal, { for object literal, @ for decorator, function, class, null, true, false, number, bigint,
| string, regexp, ` for template literal, (, or an identifier
x Expression expected
,-[$DIR/tests/jsx/errors/attribute-empty-expression/input.js:1:1]
1 | <foo bar={} />
: ^
Expand Down
Expand Up @@ -2,12 +2,6 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/jsx/errors/issue-387-5/input.js:1:1]
1 | {a:1, b:2}
: ^
`----

Error:
> This is the expression part of an expression statement
,-[$DIR/tests/jsx/errors/issue-387-5/input.js:1:1]
1 | {a:1, b:2}
: ^^^^
: ^^|^^
: `-- This is the expression part of an expression statement
`----
Expand Up @@ -3,13 +3,6 @@
,-[$DIR/tests/test262-parser/fail/03d335d8e007f61e.js:1:1]
1 | x
2 | is y
: ^
`----

Error:
> This is the expression part of an expression statement
,-[$DIR/tests/test262-parser/fail/03d335d8e007f61e.js:1:1]
1 | x
2 | is y
: ^^
: ^| ^
: `-- This is the expression part of an expression statement
`----
Expand Up @@ -2,12 +2,6 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/test262-parser/fail/09af6db5fe41b857.js:1:1]
1 | yield v
: ^
`----

Error:
> This is the expression part of an expression statement
,-[$DIR/tests/test262-parser/fail/09af6db5fe41b857.js:1:1]
1 | yield v
: ^^^^^
: ^^|^^ ^
: `-- This is the expression part of an expression statement
`----
@@ -1,6 +1,5 @@

x Unexpected token `;`. Expected this, import, async, function, [ for array literal, { for object literal, @ for decorator, function, class, null, true, false, number, bigint, string, regexp, `
| for template literal, (, or an identifier
x Expression expected
,-[$DIR/tests/test262-parser/fail/0abefbc80bf651fa.js:1:1]
1 | for (let let;;;) {}
: ^
Expand Down
Expand Up @@ -2,12 +2,6 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/test262-parser/fail/0f512c4376a62de8.js:1:1]
1 | a enum;
: ^^^^
`----

Error:
> This is the expression part of an expression statement
,-[$DIR/tests/test262-parser/fail/0f512c4376a62de8.js:1:1]
1 | a enum;
: ^
: | ^^^^
: `-- This is the expression part of an expression statement
`----
Expand Up @@ -3,15 +3,8 @@
,-[$DIR/tests/test262-parser/fail/0ffb1c3ecf85660e.js:1:1]
1 | "Hello
2 | World"
: ^
`----

Error:
> This is the expression part of an expression statement
,-[$DIR/tests/test262-parser/fail/0ffb1c3ecf85660e.js:1:1]
1 | "Hello
2 | World"
: ^^^^^
: ^^|^^^
: `-- This is the expression part of an expression statement
`----

x Unterminated string constant
Expand Down
@@ -1,6 +1,5 @@

x Unexpected token `.`. Expected this, import, async, function, [ for array literal, { for object literal, @ for decorator, function, class, null, true, false, number, bigint, string, regexp, `
| for template literal, (, or an identifier
x Expression expected
,-[$DIR/tests/test262-parser/fail/17904d9a6b6ec31b.js:1:1]
1 | f(..a)
: ^
Expand Down
Expand Up @@ -2,12 +2,6 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/test262-parser/fail/17ee4c1ca63f700d.js:1:1]
1 | 0B12
: ^
`----

Error:
> This is the expression part of an expression statement
,-[$DIR/tests/test262-parser/fail/17ee4c1ca63f700d.js:1:1]
1 | 0B12
: ^^^
: ^|^^
: `-- This is the expression part of an expression statement
`----
Expand Up @@ -2,12 +2,6 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/test262-parser/fail/1f7f17241661662d.js:1:1]
1 | []=>0
: ^^
`----

Error:
> This is the expression part of an expression statement
,-[$DIR/tests/test262-parser/fail/1f7f17241661662d.js:1:1]
1 | []=>0
: ^^
: ^|^^
: `-- This is the expression part of an expression statement
`----
@@ -1,6 +1,5 @@

x Unexpected token `=>`. Expected this, import, async, function, [ for array literal, { for object literal, @ for decorator, function, class, null, true, false, number, bigint, string, regexp, `
| for template literal, (, or an identifier
x Expression expected
,-[$DIR/tests/test262-parser/fail/211656c4eaff2d9c.js:1:1]
1 | a
2 | => 0
Expand Down
@@ -1,6 +1,5 @@

x Unexpected token `yield`. Expected this, import, async, function, [ for array literal, { for object literal, @ for decorator, function, class, null, true, false, number, bigint, string, regexp,
| ` for template literal, (, or an identifier
x Expression expected
,-[$DIR/tests/test262-parser/fail/247e71c8786de6b6.js:1:1]
1 | (function() { "use strict"; f(yield v) })
: ^^^^^
Expand Down
Expand Up @@ -2,12 +2,6 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/test262-parser/fail/26de1e8cdfa61321.js:1:1]
1 | i + 2 = 42
: ^
`----

Error:
> This is the expression part of an expression statement
,-[$DIR/tests/test262-parser/fail/26de1e8cdfa61321.js:1:1]
1 | i + 2 = 42
: ^^^^^
: ^^|^^ ^
: `-- This is the expression part of an expression statement
`----
Expand Up @@ -2,12 +2,6 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/test262-parser/fail/2945f2ec8c9f3483.js:1:1]
1 | i #= 42
: ^
`----

Error:
> This is the expression part of an expression statement
,-[$DIR/tests/test262-parser/fail/2945f2ec8c9f3483.js:1:1]
1 | i #= 42
: ^
: | ^
: `-- This is the expression part of an expression statement
`----
Expand Up @@ -2,12 +2,6 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/test262-parser/fail/2f4d2b0c0c1f960f.js:1:1]
1 | 0b12
: ^
`----

Error:
> This is the expression part of an expression statement
,-[$DIR/tests/test262-parser/fail/2f4d2b0c0c1f960f.js:1:1]
1 | 0b12
: ^^^
: ^|^^
: `-- This is the expression part of an expression statement
`----
@@ -1,6 +1,5 @@

x Unexpected token `]`. Expected this, import, async, function, [ for array literal, { for object literal, @ for decorator, function, class, null, true, false, number, bigint, string, regexp, `
| for template literal, (, or an identifier
x Expression expected
,-[$DIR/tests/test262-parser/fail/3118eaa619345896.js:1:1]
1 | /*
2 | */]
Expand Down
@@ -1,7 +1,7 @@

x Unexpected token `...`. Expected this, import, async, function, [ for array literal, { for object literal, @ for decorator, function, class, null, true, false, number, bigint, string, regexp, `
| for template literal, (, or an identifier
x Expression expected
,-[$DIR/tests/test262-parser/fail/363ecb9e2e556694.js:1:1]
1 | new f(... ... g);
: ^^^
: ^|^ ^^^
: `-- An expression should follow '...'
`----
Expand Up @@ -2,12 +2,6 @@
x Expected ';', '}' or <eof>
,-[$DIR/tests/test262-parser/fail/37b860dbda4d4c9c.js:1:1]
1 | (function() { yield 3; })
: ^
`----

Error:
> This is the expression part of an expression statement
,-[$DIR/tests/test262-parser/fail/37b860dbda4d4c9c.js:1:1]
1 | (function() { yield 3; })
: ^^^^^
: ^^|^^ ^
: `-- This is the expression part of an expression statement
`----