diff --git a/boa_parser/src/parser/statement/declaration/lexical.rs b/boa_parser/src/parser/statement/declaration/lexical.rs index ff0e53ce8e..30a00130a1 100644 --- a/boa_parser/src/parser/statement/declaration/lexical.rs +++ b/boa_parser/src/parser/statement/declaration/lexical.rs @@ -21,6 +21,7 @@ use ast::operations::bound_names; use boa_ast::{self as ast, declaration::Variable, pattern::Pattern, Keyword, Punctuator}; use boa_interner::{Interner, Sym}; use boa_profiler::Profiler; +use rustc_hash::FxHashSet; use std::io::Read; /// Parses a lexical declaration. @@ -99,6 +100,25 @@ where cursor.expect_semicolon("lexical declaration", interner)?; } + // It is a Syntax Error if the BoundNames of BindingList contains "let". + // It is a Syntax Error if the BoundNames of BindingList contains any duplicate entries. + let bound_names = bound_names(&lexical_declaration); + let mut names = FxHashSet::default(); + for name in bound_names { + if name.sym() == Sym::LET { + return Err(Error::general( + "'let' is disallowed as a lexically bound name", + tok.span().start(), + )); + } + if !names.insert(name) { + return Err(Error::general( + "lexical name declared multiple times", + tok.span().start(), + )); + } + } + Ok(lexical_declaration) } } diff --git a/boa_parser/src/parser/statement/declaration/tests.rs b/boa_parser/src/parser/statement/declaration/tests.rs index b209c9ba57..078248147c 100644 --- a/boa_parser/src/parser/statement/declaration/tests.rs +++ b/boa_parser/src/parser/statement/declaration/tests.rs @@ -349,3 +349,14 @@ fn multiple_const_declaration() { interner, ); } + +/// Checks `LexicalDeclaration` early errors. +#[test] +fn lexical_declaration_early_errors() { + check_invalid_script("let let = 0"); + check_invalid_script("let a = 0, a = 0"); + check_invalid_script("const a = 0, a = 0"); + check_invalid_script("for (let let = 0; ; ) {}"); + check_invalid_script("for (let a = 0, a = 0; ; ) {}"); + check_invalid_script("for (const a = 0, a = 0; ; ) {}"); +}