2907c726b2
Catch parameters are largely treated as lexical declarations in the block which contains their body for the purposes of early syntax errors, with some exceptions outlined in B.3.5. This patch introduces most of those errors, except those from `eval('for (var e of ...);')` inside of a catch with a simple parameter named 'e'. Note that annex B.3.5 allows var declarations to conflict with simple catch parameters, except when the variable declaration is the init of a for-of statement. BUG=v8:5112,v8:4231 Review-Url: https://codereview.chromium.org/2109733003 Cr-Commit-Position: refs/heads/master@{#37462}
194 lines
3.0 KiB
JavaScript
194 lines
3.0 KiB
JavaScript
// Copyright 2016 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.
|
|
|
|
function checkIsRedeclarationError(code) {
|
|
try {
|
|
eval(`
|
|
checkIsRedeclarationError : {
|
|
break checkIsRedeclarationError;
|
|
${code}
|
|
}
|
|
`);
|
|
assertUnreachable();
|
|
} catch(e) {
|
|
assertInstanceof(e, SyntaxError );
|
|
assertTrue( e.toString().indexOf("has already been declared") >= 0 );
|
|
}
|
|
}
|
|
|
|
function checkIsNotRedeclarationError(code) {
|
|
assertDoesNotThrow(()=>eval(`
|
|
checkIsNotRedeclarationError_label : {
|
|
break checkIsNotRedeclarationError_label;
|
|
${code}
|
|
}
|
|
`));
|
|
}
|
|
|
|
|
|
let var_e = [
|
|
'var e',
|
|
'var {e}',
|
|
'var [e]',
|
|
'var {f:e}',
|
|
'var [[[], e]]'
|
|
];
|
|
|
|
let not_var_e = [
|
|
'var f',
|
|
'var {}',
|
|
'var {e:f}',
|
|
'e',
|
|
'{e}',
|
|
'let e',
|
|
'const e',
|
|
'let {e}',
|
|
'const {e}',
|
|
'let [e]',
|
|
'const [e]',
|
|
'let {f:e}',
|
|
'const {f:e}'
|
|
];
|
|
|
|
// Check that `for (var ... of ...)` cannot redeclare a simple catch variable
|
|
// but `for (var ... in ...)` can.
|
|
for (let binding of var_e) {
|
|
checkIsRedeclarationError(`
|
|
try {
|
|
throw 0;
|
|
} catch(e) {
|
|
for (${binding} of []);
|
|
}
|
|
`);
|
|
|
|
checkIsNotRedeclarationError(`
|
|
try {
|
|
throw 0;
|
|
} catch(e) {
|
|
for (${binding} in []);
|
|
}
|
|
`);
|
|
}
|
|
|
|
// Check that the above error occurs even for nested catches.
|
|
for (let binding of var_e) {
|
|
checkIsRedeclarationError(`
|
|
try {
|
|
throw 0;
|
|
} catch(e) {
|
|
try {
|
|
throw 1;
|
|
} catch(f) {
|
|
try {
|
|
throw 2;
|
|
} catch({}) {
|
|
for (${binding} of []);
|
|
}
|
|
}
|
|
}
|
|
`);
|
|
|
|
checkIsNotRedeclarationError(`
|
|
try {
|
|
throw 0;
|
|
} catch(e) {
|
|
try {
|
|
throw 1;
|
|
} catch(f) {
|
|
try {
|
|
throw 2;
|
|
} catch({}) {
|
|
for (${binding} in []);
|
|
}
|
|
}
|
|
}
|
|
`);
|
|
}
|
|
|
|
// Check that the above error does not occur if a declaration scope is between
|
|
// the catch and the loop.
|
|
for (let binding of var_e) {
|
|
checkIsNotRedeclarationError(`
|
|
try {
|
|
throw 0;
|
|
} catch(e) {
|
|
(()=>{for (${binding} of []);})();
|
|
}
|
|
`);
|
|
|
|
checkIsNotRedeclarationError(`
|
|
try {
|
|
throw 0;
|
|
} catch(e) {
|
|
(function(){for (${binding} of []);})();
|
|
}
|
|
`);
|
|
}
|
|
|
|
// Check that there is no error when not declaring a var named e.
|
|
for (let binding of not_var_e) {
|
|
checkIsNotRedeclarationError(`
|
|
try {
|
|
throw 0;
|
|
} catch(e) {
|
|
for (${binding} of []);
|
|
}
|
|
`);
|
|
}
|
|
|
|
// Check that there is an error for both for-in and for-of when redeclaring
|
|
// a non-simple catch parameter
|
|
for (let binding of var_e) {
|
|
checkIsRedeclarationError(`
|
|
try {
|
|
throw 0;
|
|
} catch({e}) {
|
|
for (${binding} of []);
|
|
}
|
|
`);
|
|
|
|
checkIsRedeclarationError(`
|
|
try {
|
|
throw 0;
|
|
} catch({e}) {
|
|
for (${binding} in []);
|
|
}
|
|
`);
|
|
}
|
|
|
|
// Check that the above error occurs even for nested catches.
|
|
for (let binding of var_e) {
|
|
checkIsRedeclarationError(`
|
|
try {
|
|
throw 0;
|
|
} catch({e}) {
|
|
try {
|
|
throw 1;
|
|
} catch(f) {
|
|
try {
|
|
throw 2;
|
|
} catch({}) {
|
|
for (${binding} of []);
|
|
}
|
|
}
|
|
}
|
|
`);
|
|
|
|
checkIsRedeclarationError(`
|
|
try {
|
|
throw 0;
|
|
} catch({e}) {
|
|
try {
|
|
throw 1;
|
|
} catch(f) {
|
|
try {
|
|
throw 2;
|
|
} catch({}) {
|
|
for (${binding} in []);
|
|
}
|
|
}
|
|
}
|
|
`);
|
|
}
|