summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--js/src/frontend/NameAnalysisTypes.h2
-rw-r--r--js/src/frontend/Parser.cpp28
-rw-r--r--js/src/jit-test/modules/export-default-async-asi.js2
-rw-r--r--js/src/jit-test/tests/modules/function-redeclaration.js94
4 files changed, 121 insertions, 5 deletions
diff --git a/js/src/frontend/NameAnalysisTypes.h b/js/src/frontend/NameAnalysisTypes.h
index b94ca6cc0..2d327c827 100644
--- a/js/src/frontend/NameAnalysisTypes.h
+++ b/js/src/frontend/NameAnalysisTypes.h
@@ -78,6 +78,7 @@ enum class DeclarationKind : uint8_t
Const,
Import,
BodyLevelFunction,
+ ModuleBodyLevelFunction,
LexicalFunction,
VarForAnnexBLexicalFunction,
SimpleCatchParameter,
@@ -95,6 +96,7 @@ DeclarationKindToBindingKind(DeclarationKind kind)
case DeclarationKind::Var:
case DeclarationKind::BodyLevelFunction:
+ case DeclarationKind::ModuleBodyLevelFunction:
case DeclarationKind::VarForAnnexBLexicalFunction:
case DeclarationKind::ForOfVar:
return BindingKind::Var;
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index c96e8c065..d62a26f76 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -119,6 +119,7 @@ DeclarationKindString(DeclarationKind kind)
case DeclarationKind::Import:
return "import";
case DeclarationKind::BodyLevelFunction:
+ case DeclarationKind::ModuleBodyLevelFunction:
case DeclarationKind::LexicalFunction:
return "function";
case DeclarationKind::VarForAnnexBLexicalFunction:
@@ -1380,6 +1381,24 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind
break;
}
+ case DeclarationKind::ModuleBodyLevelFunction: {
+ MOZ_ASSERT(pc->atModuleLevel());
+
+ AddDeclaredNamePtr p = pc->varScope().lookupDeclaredNameForAdd(name);
+ if (p) {
+ reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
+ return false;
+ }
+
+ if (!pc->varScope().addDeclaredName(pc, p, name, kind, pos.begin))
+ return false;
+
+ // Body-level functions in modules are always closed over.
+ pc->varScope().lookupDeclaredName(name)->value()->setClosedOver();
+
+ break;
+ }
+
case DeclarationKind::FormalParameter: {
// It is an early error if any non-positional formal parameter name
// (e.g., destructuring formal parameter) is duplicated.
@@ -3750,12 +3769,11 @@ Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHan
if (!noteDeclaredName(name, DeclarationKind::LexicalFunction, pos()))
return null();
} else {
- if (!noteDeclaredName(name, DeclarationKind::BodyLevelFunction, pos()))
+ DeclarationKind kind = pc->atModuleLevel()
+ ? DeclarationKind::ModuleBodyLevelFunction
+ : DeclarationKind::BodyLevelFunction;
+ if (!noteDeclaredName(name, kind, pos()))
return null();
-
- // Body-level functions in modules are always closed over.
- if (pc->atModuleLevel())
- pc->varScope().lookupDeclaredName(name)->value()->setClosedOver();
}
Node pn = handler.newFunctionStatement();
diff --git a/js/src/jit-test/modules/export-default-async-asi.js b/js/src/jit-test/modules/export-default-async-asi.js
new file mode 100644
index 000000000..a69a7aa3d
--- /dev/null
+++ b/js/src/jit-test/modules/export-default-async-asi.js
@@ -0,0 +1,2 @@
+export default async // ASI occurs here due to the [no LineTerminator here] restriction on default-exporting an async function
+function async() { return 17; }
diff --git a/js/src/jit-test/tests/modules/function-redeclaration.js b/js/src/jit-test/tests/modules/function-redeclaration.js
new file mode 100644
index 000000000..b84704641
--- /dev/null
+++ b/js/src/jit-test/tests/modules/function-redeclaration.js
@@ -0,0 +1,94 @@
+load(libdir + "asserts.js");
+
+var functionDeclarations = [
+ "function f(){}",
+ "function* f(){}",
+ "async function f(){}",
+];
+
+var varDeclarations = [
+ "var f",
+ "{ var f; }",
+ "for (var f in null);",
+ "for (var f of null);",
+ "for (var f; ;);",
+];
+
+var lexicalDeclarations = [
+ "let f;",
+ "const f = 0;",
+ "class f {};",
+];
+
+var imports = [
+ "import f from '';",
+ "import f, {} from '';",
+ "import d, {f} from '';",
+ "import d, {f as f} from '';",
+ "import d, {foo as f} from '';",
+ "import f, * as d from '';",
+ "import d, * as f from '';",
+ "import {f} from '';",
+ "import {f as f} from '';",
+ "import {foo as f} from '';",
+ "import* as f from '';",
+];
+
+var exports = [
+ "export var f;",
+ ...functionDeclarations.map(fn => `export ${fn};`),
+ ...lexicalDeclarations.map(ld => `export ${ld};`),
+ ...functionDeclarations.map(fn => `export default ${fn};`),
+ "export default class f {};",
+];
+
+var redeclarations = [
+ ...functionDeclarations,
+ ...varDeclarations,
+ ...lexicalDeclarations,
+ ...imports,
+ ...exports,
+];
+
+var noredeclarations = [
+ ...functionDeclarations.map(fn => `{ ${fn} }`),
+ ...lexicalDeclarations.map(ld => `{ ${ld} }`),
+ ...["let", "const"].map(ld => `for (${ld} f in null);`),
+ ...["let", "const"].map(ld => `for (${ld} f of null);`),
+ ...["let", "const"].map(ld => `for (${ld} f = 0; ;);`),
+ "export {f};",
+ "export {f as f};",
+ "export {foo as f}; var foo;",
+ "export {f} from '';",
+ "export {f as f} from '';",
+ "export {foo as f} from '';",
+];
+
+for (var decl of functionDeclarations) {
+ for (var redecl of redeclarations) {
+ assertThrowsInstanceOf(() => {
+ parseModule(`
+ ${decl}
+ ${redecl}
+ `);
+ }, SyntaxError);
+
+ assertThrowsInstanceOf(() => {
+ parseModule(`
+ ${redecl}
+ ${decl}
+ `);
+ }, SyntaxError);
+ }
+
+ for (var redecl of noredeclarations) {
+ parseModule(`
+ ${decl}
+ ${redecl}
+ `);
+ parseModule(`
+ ${redecl}
+ ${decl}
+ `);
+ }
+}