Skip to content

Commit a7659c3

Browse files
committed
fix lexically-declared names in nested blocks
1 parent 668133f commit a7659c3

File tree

3 files changed

+59
-2
lines changed

3 files changed

+59
-2
lines changed

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,34 @@
66

77
The character tables that determine which characters form valid JavaScript identifiers have been updated from Unicode version 14.0.0 to the newly-released Unicode version 15.0.0. I'm not putting an example in the release notes because all of the new characters will likely just show up as little squares since fonts haven't been updated yet. But you can read https://www.unicode.org/versions/Unicode15.0.0/#Summary for more information about the changes.
88

9+
* Disallow duplicate lexically-declared names in nested blocks
10+
11+
It's supposed to be a syntax error for a nested block to declare two symbols with the same name unless all duplicate entries are either `function` declarations or all `var` declarations. However, esbuild was overly permissive and allowed this when duplicate entries were either `function` declarations or `var` declarations (even if they were mixed). This check has now been made more restrictive to match the JavaScript specification:
12+
13+
```js
14+
// JavaScript allows this
15+
var a
16+
function a() {}
17+
{
18+
var b
19+
var b
20+
function c() {}
21+
function c() {}
22+
}
23+
24+
// JavaScript doesn't allow this
25+
{
26+
var d
27+
function d() {}
28+
}
29+
```
30+
31+
* Add a type declaration for the new `empty` loader ([#2755](https://github.com/evanw/esbuild/pull/2755))
32+
33+
I forgot to add this in the previous release. It has now been added.
34+
35+
This fix was contributed by [@fz6m](https://github.com/fz6m).
36+
937
## 0.16.8
1038

1139
* Allow plugins to resolve injected files ([#2754](https://github.com/evanw/esbuild/issues/2754))

internal/js_parser/js_parser.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,8 +1163,10 @@ func (p *parser) canMergeSymbols(scope *js_ast.Scope, existing js_ast.SymbolKind
11631163
// "function foo() {} var foo;"
11641164
// "function *foo() {} function *foo() {}" but not "{ function *foo() {} function *foo() {} }"
11651165
if new.IsHoistedOrFunction() && existing.IsHoistedOrFunction() &&
1166-
(scope.Kind == js_ast.ScopeEntry || scope.Kind == js_ast.ScopeFunctionBody ||
1167-
(new.IsHoisted() && existing.IsHoisted())) {
1166+
(scope.Kind == js_ast.ScopeEntry ||
1167+
scope.Kind == js_ast.ScopeFunctionBody ||
1168+
scope.Kind == js_ast.ScopeFunctionArgs ||
1169+
(new == existing && new.IsHoisted())) {
11681170
return mergeReplaceWithNew
11691171
}
11701172

internal/js_parser/js_parser_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,33 @@ func TestFunction(t *testing.T) {
14461446
expectPrintedMangle(t, "function f() { x() } function f() { y() } var f", "function f() {\n y();\n}\nvar f;\n")
14471447
expectPrintedMangle(t, "function f() { x() } var f; function f() { y() }", "function f() {\n x();\n}\nvar f;\nfunction f() {\n y();\n}\n")
14481448
expectPrintedMangle(t, "export function f() { x() } function f() { y() }", "export function f() {\n x();\n}\nfunction f() {\n y();\n}\n")
1449+
1450+
redeclaredError := "<stdin>: ERROR: The symbol \"f\" has already been declared\n" +
1451+
"<stdin>: NOTE: The symbol \"f\" was originally declared here:\n"
1452+
1453+
expectParseError(t, "function *f() {} function *f() {}", "")
1454+
expectParseError(t, "function f() {} let f", redeclaredError)
1455+
expectParseError(t, "function f() {} var f", "")
1456+
expectParseError(t, "function *f() {} var f", "")
1457+
expectParseError(t, "let f; function f() {}", redeclaredError)
1458+
expectParseError(t, "var f; function f() {}", "")
1459+
expectParseError(t, "var f; function *f() {}", "")
1460+
1461+
expectParseError(t, "{ function *f() {} function *f() {} }", redeclaredError)
1462+
expectParseError(t, "{ function f() {} let f }", redeclaredError)
1463+
expectParseError(t, "{ function f() {} var f }", redeclaredError)
1464+
expectParseError(t, "{ function *f() {} var f }", redeclaredError)
1465+
expectParseError(t, "{ let f; function f() {} }", redeclaredError)
1466+
expectParseError(t, "{ var f; function f() {} }", redeclaredError)
1467+
expectParseError(t, "{ var f; function *f() {} }", redeclaredError)
1468+
1469+
expectParseError(t, "switch (0) { case 1: function *f() {} default: function *f() {} }", redeclaredError)
1470+
expectParseError(t, "switch (0) { case 1: function f() {} default: let f }", redeclaredError)
1471+
expectParseError(t, "switch (0) { case 1: function f() {} default: var f }", redeclaredError)
1472+
expectParseError(t, "switch (0) { case 1: function *f() {} default: var f }", redeclaredError)
1473+
expectParseError(t, "switch (0) { case 1: let f; default: function f() {} }", redeclaredError)
1474+
expectParseError(t, "switch (0) { case 1: var f; default: function f() {} }", redeclaredError)
1475+
expectParseError(t, "switch (0) { case 1: var f; default: function *f() {} }", redeclaredError)
14491476
}
14501477

14511478
func TestClass(t *testing.T) {

0 commit comments

Comments
 (0)