diff --git a/.github/workflows/cargo.yml b/.github/workflows/cargo.yml index 2a5056d298e9..bd916bab6359 100644 --- a/.github/workflows/cargo.yml +++ b/.github/workflows/cargo.yml @@ -16,6 +16,8 @@ env: CARGO_INCREMENTAL: 0 RUST_LOG: "debug" DIFF: 0 + # https://github.com/swc-project/swc/pull/3742 + RUST_MIN_STACK: 4194304 jobs: check-license: diff --git a/crates/swc_ecma_codegen/src/stmt.rs b/crates/swc_ecma_codegen/src/stmt.rs index 6442de4a233a..edbc22916f74 100644 --- a/crates/swc_ecma_codegen/src/stmt.rs +++ b/crates/swc_ecma_codegen/src/stmt.rs @@ -42,13 +42,11 @@ mod tests { fn declaration_statement() { assert_min("var foo;", "var foo"); assert_min("let foo;", "let foo"); - assert_min("const foo;", "const foo"); assert_min("var foo = 10;", "var foo=10"); assert_min("let foo = 10;", "let foo=10"); assert_min("const foo = 10;", "const foo=10"); assert_min("var foo, bar;", "var foo,bar"); assert_min("let foo, bar;", "let foo,bar"); - assert_min("const foo, bar;", "const foo,bar"); assert_min("var foo = 10, bar = 20;", "var foo=10,bar=20"); assert_min("let foo = 10, bar = 20;", "let foo=10,bar=20"); assert_min("const foo = 10, bar = 20;", "const foo=10,bar=20"); diff --git a/crates/swc_ecma_parser/src/error.rs b/crates/swc_ecma_parser/src/error.rs index f85c7b7f968c..0087ba5bba13 100644 --- a/crates/swc_ecma_parser/src/error.rs +++ b/crates/swc_ecma_parser/src/error.rs @@ -183,6 +183,8 @@ pub enum SyntaxError { ImportBindingIsString(JsWord), ExportBindingIsString, + ConstDeclarationsRequireInitialization, + TS1003, TS1005, TS1009, @@ -487,6 +489,10 @@ impl SyntaxError { "A string literal cannot be used as an exported binding without `from`.".into() } + SyntaxError::ConstDeclarationsRequireInitialization => { + "'const' declarations must be initialized".into() + } + SyntaxError::TS1003 => "Expected an identifier".into(), SyntaxError::TS1005 => "Expected a semicolon".into(), SyntaxError::TS1009 => "Trailing comma is not allowed".into(), diff --git a/crates/swc_ecma_parser/src/parser/stmt.rs b/crates/swc_ecma_parser/src/parser/stmt.rs index 4c2db0fcdac6..2f5a1c3111fd 100644 --- a/crates/swc_ecma_parser/src/parser/stmt.rs +++ b/crates/swc_ecma_parser/src/parser/stmt.rs @@ -727,7 +727,7 @@ impl<'a, I: Tokens> Parser { break; } - decls.push(self.with_ctx(ctx).parse_var_declarator(for_loop)?); + decls.push(self.with_ctx(ctx).parse_var_declarator(for_loop, kind)?); } if !for_loop && !eat!(self, ';') { @@ -748,7 +748,11 @@ impl<'a, I: Tokens> Parser { }) } - fn parse_var_declarator(&mut self, for_loop: bool) -> PResult { + fn parse_var_declarator( + &mut self, + for_loop: bool, + kind: VarDeclKind, + ) -> PResult { let start = cur_pos!(self); let mut name = self.parse_binding_pat_or_ident()?; @@ -798,6 +802,13 @@ impl<'a, I: Tokens> Parser { // Destructuring bindings require initializers, but // typescript allows `declare` vars not to have initializers. if self.ctx().in_declare { + None + } else if kind == VarDeclKind::Const && self.ctx().strict { + self.emit_err( + span!(self, start), + SyntaxError::ConstDeclarationsRequireInitialization, + ); + None } else { match name { @@ -2214,4 +2225,36 @@ export default function waitUntil(callback, options = {}) { let src = "export { 'foo' };"; test_parser(src, Syntax::Es(Default::default()), |p| p.parse_module()); } + + #[test] + #[should_panic(expected = "'const' declarations must be initialized")] + fn ts_error_for_const_declaration_not_initialized() { + let src = r#" +"use strict"; +const foo;"#; + + test_parser( + src, + Syntax::Typescript(TsConfig { + ..Default::default() + }), + |p| p.parse_script(), + ); + } + + #[test] + #[should_panic(expected = "'const' declarations must be initialized")] + fn es_error_for_const_declaration_not_initialized() { + let src = r#" +"use strict"; +const foo;"#; + + test_parser( + src, + Syntax::Es(EsConfig { + ..Default::default() + }), + |p| p.parse_script(), + ); + } }