diff --git a/lib/scope.js b/lib/scope.js index e7e6283e..47ea7122 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -203,6 +203,21 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ || node instanceof AST_SymbolLet || node instanceof AST_SymbolConst) { var def = ((node instanceof AST_SymbolBlockDeclaration) ? scope : defun).def_variable(node); + if (!all(def.orig, function(sym) { + if (sym === node) return true; + if (node instanceof AST_SymbolBlockDeclaration) { + return sym instanceof AST_SymbolLambda; + } + return !(sym instanceof AST_SymbolLet || sym instanceof AST_SymbolConst); + })) { + js_error( + node.name + " redeclared", + node.start.file, + node.start.line, + node.start.col, + node.start.pos + ); + } if (!(node instanceof AST_SymbolFunarg)) mark_export(def, 2); def.destructuring = in_destructuring; if (defun !== scope) { @@ -357,7 +372,7 @@ AST_IterationStatement.DEFMETHOD("is_block_scope", return_true); AST_Lambda.DEFMETHOD("init_scope_vars", function(){ AST_Scope.prototype.init_scope_vars.apply(this, arguments); this.uses_arguments = false; - this.def_variable(new AST_SymbolConst({ + this.def_variable(new AST_SymbolFunarg({ name: "arguments", start: this.start, end: this.end diff --git a/test/compress/destructuring.js b/test/compress/destructuring.js index 0c85e432..cfda28db 100644 --- a/test/compress/destructuring.js +++ b/test/compress/destructuring.js @@ -65,10 +65,10 @@ nested_destructuring_objects: { } input: { const [{a},b] = c; - let [{a},b] = c; - var [{a},b] = c; + let [{d},e] = f; + var [{g},h] = i; } - expect_exact: 'const[{a},b]=c;let[{a},b]=c;var[{a},b]=c;'; + expect_exact: 'const[{a},b]=c;let[{d},e]=f;var[{g},h]=i;'; } destructuring_constdef_in_loops: { @@ -274,8 +274,8 @@ reduce_vars: { var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}}; ({aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}}); const [{a},b] = c; - let [{a},b] = c; - var [{a},b] = c; + let [{d},e] = f; + var [{g},h] = i; [{a},b] = c; for (const [x,y] in pairs); for (let [x,y] in pairs); @@ -292,8 +292,8 @@ reduce_vars: { var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}}; ({aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}}); const [{a},b] = c; - let [{a},b] = c; - var [{a},b] = c; + let [{d},e] = f; + var [{g},h] = i; [{a},b] = c; for (const [x,y] in pairs); for (let [x,y] in pairs); diff --git a/test/compress/harmony.js b/test/compress/harmony.js index 2e8fe38b..6078dd98 100644 --- a/test/compress/harmony.js +++ b/test/compress/harmony.js @@ -211,13 +211,13 @@ export_statement: { } input: { export default 1 + 2; - export var foo = 4; - export let foo = 6; - export const foo = 6; - export function foo() {}; - export class foo { }; + export var a = 4; + export let b = 6; + export const c = 6; + export function d() {}; + export class e {}; } - expect_exact: "export default 3;export var foo=4;export let foo=6;export const foo=6;export function foo(){};export class foo{};" + expect_exact: "export default 3;export var a=4;export let b=6;export const c=6;export function d(){};export class e{};" } export_default_object_expression: { diff --git a/test/compress/parameters.js b/test/compress/parameters.js index d141fff1..94c23914 100644 --- a/test/compress/parameters.js +++ b/test/compress/parameters.js @@ -142,11 +142,11 @@ destructuring_arguments_3: { } input: { function fn3({x: {y: {z: {} = 42}}}) {} - const { cover = (function () {}), xCover = (0, function() {}) } = {}; - let { cover = (function () {}), xCover = (0, function() {}) } = {}; - var { cover = (function () {}), xCover = (0, function() {}) } = {}; + const { a = (function () {}), b = (0, function() {}) } = {}; + let { c = (function () {}), d = (0, function() {}) } = {}; + var { e = (function () {}), f = (0, function() {}) } = {}; } - expect_exact: "function fn3({x:{y:{z:{}=42}}}){}const{cover=function(){},xCover=(0,function(){})}={};let{cover=function(){},xCover=(0,function(){})}={};var{cover=function(){},xCover=(0,function(){})}={};" + expect_exact: "function fn3({x:{y:{z:{}=42}}}){}const{a=function(){},b=(0,function(){})}={};let{c=function(){},d=(0,function(){})}={};var{e=function(){},f=(0,function(){})}={};" } default_arguments: { diff --git a/test/mocha/minify.js b/test/mocha/minify.js index fc7332fb..376b6a50 100644 --- a/test/mocha/minify.js +++ b/test/mocha/minify.js @@ -291,4 +291,34 @@ describe("minify", function() { assert.strictEqual(result.code, "alert({bar:42});"); }); }); + + describe("duplicated block-scoped declarations", function() { + [ + "let a=1;let a=2;", + "let a=1;var a=2;", + "var a=1;let a=2;", + "let[a]=[1];var a=2;", + "let a=1;var[a]=[2];", + "let[a]=[1];var[a]=[2];", + "const a=1;const a=2;", + "const a=1;var a=2;", + "var a=1;const a=2;", + "const[a]=[1];var a=2;", + "const a=1;var[a]=[2];", + "const[a]=[1];var[a]=[2];", + ].forEach(function(code) { + it(code, function() { + var result = Uglify.minify(code, { + compress: false, + mangle: false + }); + assert.strictEqual(result.error, undefined); + assert.strictEqual(result.code, code); + result = Uglify.minify(code); + var err = result.error; + assert.ok(err instanceof Error); + assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: a redeclared"); + }); + }); + }); });