1340148 - Disallow function redeclarations at module top level.

This commit is contained in:
Fedor 2019-09-05 20:06:33 +03:00
parent bc64f5e333
commit 0154fa01b6
4 changed files with 121 additions and 5 deletions

View File

@ -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;

View File

@ -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();

View File

@ -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; }

View File

@ -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}
`);
}
}