4424f5d1de
ExpressionClassifier was used just for transmitting information back and forth to DeclareFormalParameters. As a bonus, we now do the Scope::IsDeclaredParameter check only when we're going to use the information it produces. BUG=v8:6092,v8:6474 Change-Id: Ib5ac6a779705caa74e933e1c6f03eaaf0f49bf05 Reviewed-on: https://chromium-review.googlesource.com/455836 Commit-Queue: Marja Hölttä <marja@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Cr-Commit-Position: refs/heads/master@{#45809}
180 lines
7.1 KiB
JavaScript
180 lines
7.1 KiB
JavaScript
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
/*
|
|
- Duplicate parameters are allowed for
|
|
- non-arrow functions which are not conscise methods *and*
|
|
- when the parameter list is simple *and*
|
|
- we're in sloppy mode (incl. the function doesn't declare itself strict).
|
|
*/
|
|
|
|
function assertDuplicateParametersError(code) {
|
|
caught = false;
|
|
try {
|
|
eval(code);
|
|
} catch(e) {
|
|
// Assert that it's the duplicate parameters error, and e.g,. not a syntax
|
|
// error because of a typo in the test.
|
|
assertTrue(e.message.startsWith("Duplicate parameter name not allowed"));
|
|
caught = true;
|
|
} finally {
|
|
assertTrue(caught);
|
|
}
|
|
}
|
|
|
|
FunctionType = {
|
|
NORMAL : 0,
|
|
ARROW : 1,
|
|
METHOD : 2,
|
|
CONCISE_METHOD : 3,
|
|
};
|
|
|
|
Laziness = {
|
|
EAGER : 0,
|
|
LAZY_BOUNDARY : 1,
|
|
LAZY : 2
|
|
};
|
|
|
|
Strictness = {
|
|
SLOPPY : 0,
|
|
STRICT : 1,
|
|
STRICT_FUNCTION : 2
|
|
};
|
|
|
|
function testHelper(type, strict, lazy, duplicate_params_string, ok) {
|
|
code = ""
|
|
strict_inside = "";
|
|
if (strict == Strictness.STRICT) {
|
|
code = "'use strict'; ";
|
|
} else if (strict == Strictness.STRICT_FUNCTION) {
|
|
strict_inside = "'use strict'; ";
|
|
} else {
|
|
assertEquals(strict, Strictness.SLOPPY);
|
|
}
|
|
|
|
if (type == FunctionType.NORMAL) {
|
|
if (lazy == Laziness.EAGER) {
|
|
code += "(function foo(" + duplicate_params_string + ") { " + strict_inside + "})";
|
|
} else if (lazy == Laziness.LAZY_BOUNDARY) {
|
|
code += "function foo(" + duplicate_params_string + ") { " + strict_inside + "}";
|
|
} else if (lazy == Laziness.LAZY) {
|
|
code += 'function lazy() { function foo(' + duplicate_params_string +
|
|
') { ' + strict_inside + '} }';
|
|
} else {
|
|
assertUnreachable();
|
|
}
|
|
} else if (type == FunctionType.ARROW) {
|
|
if (lazy == Laziness.EAGER) {
|
|
// Force an arrow function to be eager by making its body trivial.
|
|
assertEquals(strict, Strictness.SLOPPY);
|
|
code += "(" + duplicate_params_string + ") => 1";
|
|
} else if (lazy == Laziness.LAZY_BOUNDARY) {
|
|
// Duplicate parameters in non-simple parameter lists are not recognized
|
|
// at the laziness boundary, when the lazy function is an arrow
|
|
// function. Hack around this by calling the function. See
|
|
// https://bugs.chromium.org/p/v8/issues/detail?id=6108.
|
|
let simple = /^[a-z, ]*$/.test(duplicate_params_string);
|
|
if (simple) {
|
|
code += "(" + duplicate_params_string + ") => { " + strict_inside + "};";
|
|
} else {
|
|
code += "let foo = (" + duplicate_params_string + ") => { " + strict_inside + "}; foo();";
|
|
}
|
|
} else if (lazy == Laziness.LAZY) {
|
|
// PreParser cannot detect duplicates in arrow function parameters. When
|
|
// parsing the parameter list, it doesn't know it's an arrow function
|
|
// parameter list, so it just discards the identifiers, and cannot do the
|
|
// check any more when it sees the arrow. Work around this by calling the
|
|
// function which forces parsing it.
|
|
code += 'function lazy() { (' + duplicate_params_string + ') => { ' +
|
|
strict_inside + '} } lazy();';
|
|
} else {
|
|
assertUnreachable();
|
|
}
|
|
} else if (type == FunctionType.METHOD) {
|
|
code += "var o = {";
|
|
if (lazy == Laziness.EAGER) {
|
|
code += "foo : (function(" + duplicate_params_string + ") { " + strict_inside + "})";
|
|
} else if (lazy == Laziness.LAZY_BOUNDARY) {
|
|
code += "foo : function(" + duplicate_params_string + ") { " + strict_inside + "}";
|
|
} else if (lazy == Laziness.LAZY) {
|
|
code += 'lazy: function() { function foo(' + duplicate_params_string +
|
|
') { ' + strict_inside + '} }';
|
|
} else {
|
|
assertUnreachable();
|
|
}
|
|
code += "};";
|
|
} else if (type == FunctionType.CONCISE_METHOD) {
|
|
if (lazy == Laziness.LAZY_BOUNDARY) {
|
|
code += "var o = { foo(" + duplicate_params_string + ") { " + strict_inside + "} };";
|
|
} else if (lazy == Laziness.LAZY) {
|
|
code += 'function lazy() { var o = { foo(' + duplicate_params_string +
|
|
') { ' + strict_inside + '} }; }';
|
|
} else {
|
|
assertUnreachable();
|
|
}
|
|
} else {
|
|
assertUnreachable();
|
|
}
|
|
|
|
if (ok) {
|
|
assertDoesNotThrow(code);
|
|
} else {
|
|
assertDuplicateParametersError(code);
|
|
}
|
|
}
|
|
|
|
function test(type, strict, lazy, ok_if_param_list_simple) {
|
|
// Simple duplicate params.
|
|
testHelper(type, strict, lazy, "a, dup, dup, b", ok_if_param_list_simple)
|
|
|
|
if (strict != Strictness.STRICT_FUNCTION) {
|
|
// Generate test cases where the duplicate parameter occurs because of
|
|
// destructuring or the rest parameter. That is always an error: duplicate
|
|
// parameters are only allowed in simple parameter lists. These tests are
|
|
// not possible if a function declares itself strict, since non-simple
|
|
// parameters are not allowed then.
|
|
testHelper(type, strict, lazy, "a, [dup], dup, b", false);
|
|
testHelper(type, strict, lazy, "a, dup, {b: dup}, c", false);
|
|
testHelper(type, strict, lazy, "a, {dup}, [dup], b", false);
|
|
testHelper(type, strict, lazy, "a, dup, ...dup", false);
|
|
testHelper(type, strict, lazy, "a, dup, dup, ...rest", false);
|
|
testHelper(type, strict, lazy, "a, dup, dup, b = 1", false);
|
|
}
|
|
}
|
|
|
|
// No duplicate parameters allowed for arrow functions even in sloppy mode.
|
|
test(FunctionType.ARROW, Strictness.SLOPPY, Laziness.EAGER, false);
|
|
test(FunctionType.ARROW, Strictness.SLOPPY, Laziness.LAZY_BOUNDARY, false);
|
|
test(FunctionType.ARROW, Strictness.SLOPPY, Laziness.LAZY, false);
|
|
|
|
// Duplicate parameters allowed for normal functions in sloppy mode.
|
|
test(FunctionType.NORMAL, Strictness.SLOPPY, Laziness.EAGER, true);
|
|
test(FunctionType.NORMAL, Strictness.SLOPPY, Laziness.LAZY_BOUNDARY, true);
|
|
test(FunctionType.NORMAL, Strictness.SLOPPY, Laziness.LAZY, true);
|
|
|
|
test(FunctionType.NORMAL, Strictness.STRICT, Laziness.EAGER, false);
|
|
test(FunctionType.NORMAL, Strictness.STRICT, Laziness.LAZY_BOUNDARY, false);
|
|
test(FunctionType.NORMAL, Strictness.STRICT, Laziness.LAZY, false);
|
|
|
|
test(FunctionType.NORMAL, Strictness.STRICT_FUNCTION, Laziness.EAGER, false);
|
|
test(FunctionType.NORMAL, Strictness.STRICT_FUNCTION, Laziness.LAZY_BOUNDARY, false);
|
|
test(FunctionType.NORMAL, Strictness.STRICT_FUNCTION, Laziness.LAZY, false);
|
|
|
|
// No duplicate parameters allowed for conscise methods even in sloppy mode.
|
|
test(FunctionType.CONCISE_METHOD, Strictness.SLOPPY, Laziness.LAZY_BOUNDARY, false);
|
|
test(FunctionType.CONCISE_METHOD, Strictness.SLOPPY, Laziness.LAZY, false);
|
|
|
|
// But non-concise methods follow the rules for normal funcs.
|
|
test(FunctionType.METHOD, Strictness.SLOPPY, Laziness.EAGER, true);
|
|
test(FunctionType.METHOD, Strictness.SLOPPY, Laziness.LAZY_BOUNDARY, true);
|
|
test(FunctionType.METHOD, Strictness.SLOPPY, Laziness.LAZY, true);
|
|
|
|
test(FunctionType.METHOD, Strictness.STRICT, Laziness.EAGER, false);
|
|
test(FunctionType.METHOD, Strictness.STRICT, Laziness.LAZY_BOUNDARY, false);
|
|
test(FunctionType.METHOD, Strictness.STRICT, Laziness.LAZY, false);
|
|
|
|
test(FunctionType.METHOD, Strictness.STRICT_FUNCTION, Laziness.EAGER, false);
|
|
test(FunctionType.METHOD, Strictness.STRICT_FUNCTION, Laziness.LAZY_BOUNDARY, false);
|
|
test(FunctionType.METHOD, Strictness.STRICT_FUNCTION, Laziness.LAZY, false);
|