|  | // 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); |