From c6c939fb87f8bfdfad1cbea70cec4cfa9fbc66d5 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 28 Aug 2020 17:03:31 +0200 Subject: [PATCH] Extract hoisted variables from dead branches (#3752) * Extract hoisted variables from dead branches * Improve coverage --- src/ast/nodes/Identifier.ts | 3 +- src/ast/nodes/IfStatement.ts | 95 ++++++++++++++----- src/ast/nodes/VariableDeclarator.ts | 12 --- src/ast/scopes/BlockScope.ts | 11 +-- src/ast/scopes/CatchScope.ts | 2 +- src/ast/scopes/Scope.ts | 4 +- src/ast/scopes/TrackingScope.ts | 19 ++++ .../hoisted-unused-conditional/_expected.js | 4 +- .../hoisted-variable-if-stmt/_expected.js | 4 +- .../hoisted-vars-in-dead-branches/_config.js | 3 + .../_expected.js | 6 ++ .../hoisted-vars-in-dead-branches/main.js | 12 +++ .../{_expected/es.js => _expected.js} | 5 + .../samples/no-treeshake/_expected/amd.js | 59 ------------ .../samples/no-treeshake/_expected/cjs.js | 59 ------------ .../samples/no-treeshake/_expected/iife.js | 60 ------------ .../samples/no-treeshake/_expected/system.js | 61 ------------ .../samples/no-treeshake/_expected/umd.js | 63 ------------ test/form/samples/no-treeshake/main.js | 5 + test/form/samples/redeclarations/_expected.js | 8 ++ .../samples/redeclarations/_expected/amd.js | 24 ----- .../samples/redeclarations/_expected/cjs.js | 22 ----- .../samples/redeclarations/_expected/es.js | 20 ---- .../samples/redeclarations/_expected/iife.js | 25 ----- .../redeclarations/_expected/system.js | 29 ------ .../samples/redeclarations/_expected/umd.js | 27 ------ test/form/samples/redeclarations/main.js | 1 + .../{_expected/es.js => _expected.js} | 28 ++---- .../tree-shake-if-statements/_expected/amd.js | 61 ------------ .../tree-shake-if-statements/_expected/cjs.js | 59 ------------ .../_expected/iife.js | 62 ------------ .../_expected/system.js | 66 ------------- .../tree-shake-if-statements/_expected/umd.js | 64 ------------- .../samples/tree-shake-if-statements/main.js | 16 ++-- 34 files changed, 152 insertions(+), 847 deletions(-) create mode 100644 src/ast/scopes/TrackingScope.ts create mode 100644 test/form/samples/hoisted-vars-in-dead-branches/_config.js create mode 100644 test/form/samples/hoisted-vars-in-dead-branches/_expected.js create mode 100644 test/form/samples/hoisted-vars-in-dead-branches/main.js rename test/form/samples/no-treeshake/{_expected/es.js => _expected.js} (93%) delete mode 100644 test/form/samples/no-treeshake/_expected/amd.js delete mode 100644 test/form/samples/no-treeshake/_expected/cjs.js delete mode 100644 test/form/samples/no-treeshake/_expected/iife.js delete mode 100644 test/form/samples/no-treeshake/_expected/system.js delete mode 100644 test/form/samples/no-treeshake/_expected/umd.js create mode 100644 test/form/samples/redeclarations/_expected.js delete mode 100644 test/form/samples/redeclarations/_expected/amd.js delete mode 100644 test/form/samples/redeclarations/_expected/cjs.js delete mode 100644 test/form/samples/redeclarations/_expected/es.js delete mode 100644 test/form/samples/redeclarations/_expected/iife.js delete mode 100644 test/form/samples/redeclarations/_expected/system.js delete mode 100644 test/form/samples/redeclarations/_expected/umd.js rename test/form/samples/tree-shake-if-statements/{_expected/es.js => _expected.js} (57%) delete mode 100644 test/form/samples/tree-shake-if-statements/_expected/amd.js delete mode 100644 test/form/samples/tree-shake-if-statements/_expected/cjs.js delete mode 100644 test/form/samples/tree-shake-if-statements/_expected/iife.js delete mode 100644 test/form/samples/tree-shake-if-statements/_expected/system.js delete mode 100644 test/form/samples/tree-shake-if-statements/_expected/umd.js diff --git a/src/ast/nodes/Identifier.ts b/src/ast/nodes/Identifier.ts index c28eb3c7f3a..c2a8caa9466 100644 --- a/src/ast/nodes/Identifier.ts +++ b/src/ast/nodes/Identifier.ts @@ -59,7 +59,8 @@ export default class Identifier extends NodeBase implements PatternNode { variable = this.scope.addDeclaration(this, this.context, init, true); break; case 'function': - variable = this.scope.addDeclaration(this, this.context, init, 'function'); + // in strict mode, functions are only hoisted within a scope but not across block scopes + variable = this.scope.addDeclaration(this, this.context, init, false); break; case 'let': case 'const': diff --git a/src/ast/nodes/IfStatement.ts b/src/ast/nodes/IfStatement.ts index d0ba6f10296..b828353f53a 100644 --- a/src/ast/nodes/IfStatement.ts +++ b/src/ast/nodes/IfStatement.ts @@ -3,11 +3,19 @@ import { RenderOptions } from '../../utils/renderHelpers'; import { removeAnnotations } from '../../utils/treeshakeNode'; import { DeoptimizableEntity } from '../DeoptimizableEntity'; import { BROKEN_FLOW_NONE, HasEffectsContext, InclusionContext } from '../ExecutionContext'; +import TrackingScope from '../scopes/TrackingScope'; import { EMPTY_PATH, SHARED_RECURSION_TRACKER } from '../utils/PathTracker'; import { LiteralValueOrUnknown, UnknownValue } from '../values'; import BlockStatement from './BlockStatement'; +import Identifier from './Identifier'; import * as NodeType from './NodeType'; -import { ExpressionNode, IncludeChildren, StatementBase, StatementNode } from './shared/Node'; +import { + ExpressionNode, + GenericEsTreeNode, + IncludeChildren, + StatementBase, + StatementNode +} from './shared/Node'; const unset = Symbol('unset'); @@ -17,6 +25,8 @@ export default class IfStatement extends StatementBase implements DeoptimizableE test!: ExpressionNode; type!: NodeType.tIfStatement; + private alternateScope?: TrackingScope; + private consequentScope!: TrackingScope; private testValue: LiteralValueOrUnknown | typeof unset = unset; deoptimizeCache() { @@ -58,42 +68,62 @@ export default class IfStatement extends StatementBase implements DeoptimizableE } } + parseNode(esTreeNode: GenericEsTreeNode) { + this.consequentScope = new TrackingScope(this.scope); + this.consequent = new this.context.nodeConstructors[esTreeNode.consequent.type]( + esTreeNode.consequent, + this, + this.consequentScope + ); + if (esTreeNode.alternate) { + this.alternateScope = new TrackingScope(this.scope); + this.alternate = new this.context.nodeConstructors[esTreeNode.alternate.type]( + esTreeNode.alternate, + this, + this.alternateScope + ); + } + super.parseNode(esTreeNode); + } + render(code: MagicString, options: RenderOptions) { // Note that unknown test values are always included const testValue = this.getTestValue(); - if ( - !this.test.included && - (testValue ? this.alternate === null || !this.alternate.included : !this.consequent.included) - ) { - const singleRetainedBranch = (testValue ? this.consequent : this.alternate)!; - code.remove(this.start, singleRetainedBranch.start); - code.remove(singleRetainedBranch.end, this.end); + const hoistedDeclarations: Identifier[] = []; + const includesIfElse = this.test.included; + const noTreeshake = !this.context.options.treeshake; + if (includesIfElse) { + this.test.render(code, options); + } else { removeAnnotations(this, code); - singleRetainedBranch.render(code, options); + code.remove(this.start, this.consequent.start); + } + if (this.consequent.included && (noTreeshake || testValue === UnknownValue || testValue)) { + this.consequent.render(code, options); } else { - if (this.test.included) { - this.test.render(code, options); - } else { - code.overwrite(this.test.start, this.test.end, testValue ? 'true' : 'false'); - } - if (this.consequent.included) { - this.consequent.render(code, options); - } else { - code.overwrite(this.consequent.start, this.consequent.end, ';'); - } - if (this.alternate !== null) { - if (this.alternate.included) { - if (code.original.charCodeAt(this.alternate.start - 1) === 101 /* e */) { + code.overwrite(this.consequent.start, this.consequent.end, includesIfElse ? ';' : ''); + hoistedDeclarations.push(...this.consequentScope.hoistedDeclarations); + } + if (this.alternate) { + if (this.alternate.included && (noTreeshake || testValue === UnknownValue || !testValue)) { + if (includesIfElse) { + if (code.original.charCodeAt(this.alternate.start - 1) === 101) { code.prependLeft(this.alternate.start, ' '); } - this.alternate.render(code, options); - } else if (this.shouldKeepAlternateBranch()) { - code.overwrite(this.alternate.start, this.alternate.end, ';'); } else { - code.remove(this.consequent.end, this.alternate.end); + code.remove(this.consequent.end, this.alternate.start); + } + this.alternate.render(code, options); + } else { + if (includesIfElse && this.shouldKeepAlternateBranch()) { + code.overwrite(this.alternate.start, this.end, ';'); + } else { + code.remove(this.consequent.end, this.end); } + hoistedDeclarations.push(...this.alternateScope!.hoistedDeclarations); } } + renderHoistedDeclarations(hoistedDeclarations, this.start, code); } private getTestValue(): LiteralValueOrUnknown { @@ -160,3 +190,16 @@ export default class IfStatement extends StatementBase implements DeoptimizableE return false; } } + +function renderHoistedDeclarations( + hoistedDeclarations: Identifier[], + prependPosition: number, + code: MagicString +) { + const hoistedVars = [ + ...new Set(hoistedDeclarations.map(identifier => identifier.variable!.getName())) + ].join(', '); + if (hoistedVars) { + code.prependRight(prependPosition, `var ${hoistedVars}; `); + } +} diff --git a/src/ast/nodes/VariableDeclarator.ts b/src/ast/nodes/VariableDeclarator.ts index 4c50807afaf..9bdd786aa3d 100644 --- a/src/ast/nodes/VariableDeclarator.ts +++ b/src/ast/nodes/VariableDeclarator.ts @@ -1,5 +1,3 @@ -import MagicString from 'magic-string'; -import { RenderOptions } from '../../utils/renderHelpers'; import { ObjectPath } from '../utils/PathTracker'; import { UNDEFINED_EXPRESSION } from '../values'; import * as NodeType from './NodeType'; @@ -18,14 +16,4 @@ export default class VariableDeclarator extends NodeBase { deoptimizePath(path: ObjectPath) { this.id.deoptimizePath(path); } - - render(code: MagicString, options: RenderOptions) { - // This can happen for hoisted variables in dead branches - if (this.init !== null && !this.init.included) { - code.remove(this.id.end, this.end); - this.id.render(code, options); - } else { - super.render(code, options); - } - } } diff --git a/src/ast/scopes/BlockScope.ts b/src/ast/scopes/BlockScope.ts index d08b6767751..b72bcc3a19e 100644 --- a/src/ast/scopes/BlockScope.ts +++ b/src/ast/scopes/BlockScope.ts @@ -9,16 +9,11 @@ export default class BlockScope extends ChildScope { addDeclaration( identifier: Identifier, context: AstContext, - init: ExpressionEntity | null = null, - isHoisted: boolean | 'function' + init: ExpressionEntity | null, + isHoisted: boolean ): LocalVariable { if (isHoisted) { - return this.parent.addDeclaration( - identifier, - context, - isHoisted === 'function' ? init : UNKNOWN_EXPRESSION, - isHoisted - ); + return this.parent.addDeclaration(identifier, context, UNKNOWN_EXPRESSION, isHoisted); } else { return super.addDeclaration(identifier, context, init, false); } diff --git a/src/ast/scopes/CatchScope.ts b/src/ast/scopes/CatchScope.ts index 08e977006d8..4b59fbfe1ed 100644 --- a/src/ast/scopes/CatchScope.ts +++ b/src/ast/scopes/CatchScope.ts @@ -9,7 +9,7 @@ export default class CatchScope extends ParameterScope { identifier: Identifier, context: AstContext, init: ExpressionEntity | null, - isHoisted: boolean | 'function' + isHoisted: boolean ): LocalVariable { if (isHoisted) { return this.parent.addDeclaration(identifier, context, init, isHoisted); diff --git a/src/ast/scopes/Scope.ts b/src/ast/scopes/Scope.ts index 9b5b5bd9739..32a46d31719 100644 --- a/src/ast/scopes/Scope.ts +++ b/src/ast/scopes/Scope.ts @@ -13,8 +13,8 @@ export default class Scope { addDeclaration( identifier: Identifier, context: AstContext, - init: ExpressionEntity | null = null, - _isHoisted: boolean | 'function' + init: ExpressionEntity | null, + _isHoisted: boolean ) { const name = identifier.name; let variable = this.variables.get(name) as LocalVariable; diff --git a/src/ast/scopes/TrackingScope.ts b/src/ast/scopes/TrackingScope.ts new file mode 100644 index 00000000000..41bf1dd98eb --- /dev/null +++ b/src/ast/scopes/TrackingScope.ts @@ -0,0 +1,19 @@ +import { AstContext } from '../../Module'; +import Identifier from '../nodes/Identifier'; +import { ExpressionEntity } from '../nodes/shared/Expression'; +import LocalVariable from '../variables/LocalVariable'; +import BlockScope from './BlockScope'; + +export default class TrackingScope extends BlockScope { + public hoistedDeclarations: Identifier[] = []; + + addDeclaration( + identifier: Identifier, + context: AstContext, + init: ExpressionEntity | null, + isHoisted: boolean + ): LocalVariable { + this.hoistedDeclarations.push(identifier); + return this.parent.addDeclaration(identifier, context, init, isHoisted); + } +} diff --git a/test/form/samples/hoisted-unused-conditional/_expected.js b/test/form/samples/hoisted-unused-conditional/_expected.js index 4edef047d68..fa4bb660709 100644 --- a/test/form/samples/hoisted-unused-conditional/_expected.js +++ b/test/form/samples/hoisted-unused-conditional/_expected.js @@ -1,5 +1,3 @@ -if (false) { - var deadVariable, otherDeadVariable; -} +var deadVariable, otherDeadVariable; console.log(deadVariable, otherDeadVariable); diff --git a/test/form/samples/hoisted-variable-if-stmt/_expected.js b/test/form/samples/hoisted-variable-if-stmt/_expected.js index a7ac1cf18f7..91962940aa8 100644 --- a/test/form/samples/hoisted-variable-if-stmt/_expected.js +++ b/test/form/samples/hoisted-variable-if-stmt/_expected.js @@ -1,6 +1,4 @@ -if (false) { - var foo; -} +var foo; if (foo) { console.log("nope"); diff --git a/test/form/samples/hoisted-vars-in-dead-branches/_config.js b/test/form/samples/hoisted-vars-in-dead-branches/_config.js new file mode 100644 index 00000000000..b27559e4d8e --- /dev/null +++ b/test/form/samples/hoisted-vars-in-dead-branches/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'renders hoisted variables in dead branches' +}; diff --git a/test/form/samples/hoisted-vars-in-dead-branches/_expected.js b/test/form/samples/hoisted-vars-in-dead-branches/_expected.js new file mode 100644 index 00000000000..86e711f2715 --- /dev/null +++ b/test/form/samples/hoisted-vars-in-dead-branches/_expected.js @@ -0,0 +1,6 @@ +var a, b; { + console.log(a, b); +} + +var c, d; if (((() => console.log('effect'))(), true)) ; +console.log(c, d); diff --git a/test/form/samples/hoisted-vars-in-dead-branches/main.js b/test/form/samples/hoisted-vars-in-dead-branches/main.js new file mode 100644 index 00000000000..2c6f8f80025 --- /dev/null +++ b/test/form/samples/hoisted-vars-in-dead-branches/main.js @@ -0,0 +1,12 @@ +if (false) { + for (var a; unknownGlobal && true; unknownGlobal && true) var b; +} else { + console.log(a, b); +} + +if (((() => console.log('effect'))(), true)) { +} else { + var c = 1; + for (var c; unknownGlobal && true; unknownGlobal && true) var d; +} +console.log(c, d); diff --git a/test/form/samples/no-treeshake/_expected/es.js b/test/form/samples/no-treeshake/_expected.js similarity index 93% rename from test/form/samples/no-treeshake/_expected/es.js rename to test/form/samples/no-treeshake/_expected.js index 8570fcb406f..965b6514545 100644 --- a/test/form/samples/no-treeshake/_expected/es.js +++ b/test/form/samples/no-treeshake/_expected.js @@ -20,6 +20,11 @@ function unusedButIncluded() { } else { (true && 'first') || 'second'; } + if (false) { + 'first'; + } else { + 'second'; + } 'sequence', 'expression'; switch ('test') { case 'test': diff --git a/test/form/samples/no-treeshake/_expected/amd.js b/test/form/samples/no-treeshake/_expected/amd.js deleted file mode 100644 index 8358fa23eb0..00000000000 --- a/test/form/samples/no-treeshake/_expected/amd.js +++ /dev/null @@ -1,59 +0,0 @@ -define(['exports', 'external'], function (exports, external) { 'use strict'; - - var foo = 13; - - const quux = 1; - - const other = () => quux; - - function baz() { - return foo + external.value; - } - - var create = Object.create, - getPrototypeOf = Object.getPrototypeOf; - - function unusedButIncluded() { - const unusedConst = 'unused'; - if (true) { - true ? 'first' : 'second'; - } else { - (true && 'first') || 'second'; - } - 'sequence', 'expression'; - switch ('test') { - case 'test': - (() => {})(); - case 'other': - 'no effect'; - default: - const ignored = 2; - } - } - - function test( - unusedParam = { - prop: function test() { - var unused = 1; - } - } - ) {} - - test({ - prop: function test() { - var unused = 1; - } - }); - - try { - const x = 1; - } catch {} - - exports.create = create; - exports.getPrototypeOf = getPrototypeOf; - exports.quux = quux; - exports.strange = quux; - - Object.defineProperty(exports, '__esModule', { value: true }); - -}); diff --git a/test/form/samples/no-treeshake/_expected/cjs.js b/test/form/samples/no-treeshake/_expected/cjs.js deleted file mode 100644 index 132fbdc7110..00000000000 --- a/test/form/samples/no-treeshake/_expected/cjs.js +++ /dev/null @@ -1,59 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -var external = require('external'); - -var foo = 13; - -const quux = 1; - -const other = () => quux; - -function baz() { - return foo + external.value; -} - -var create = Object.create, - getPrototypeOf = Object.getPrototypeOf; - -function unusedButIncluded() { - const unusedConst = 'unused'; - if (true) { - true ? 'first' : 'second'; - } else { - (true && 'first') || 'second'; - } - 'sequence', 'expression'; - switch ('test') { - case 'test': - (() => {})(); - case 'other': - 'no effect'; - default: - const ignored = 2; - } -} - -function test( - unusedParam = { - prop: function test() { - var unused = 1; - } - } -) {} - -test({ - prop: function test() { - var unused = 1; - } -}); - -try { - const x = 1; -} catch {} - -exports.create = create; -exports.getPrototypeOf = getPrototypeOf; -exports.quux = quux; -exports.strange = quux; diff --git a/test/form/samples/no-treeshake/_expected/iife.js b/test/form/samples/no-treeshake/_expected/iife.js deleted file mode 100644 index d5d2cf2893d..00000000000 --- a/test/form/samples/no-treeshake/_expected/iife.js +++ /dev/null @@ -1,60 +0,0 @@ -var stirred = (function (exports, external) { - 'use strict'; - - var foo = 13; - - const quux = 1; - - const other = () => quux; - - function baz() { - return foo + external.value; - } - - var create = Object.create, - getPrototypeOf = Object.getPrototypeOf; - - function unusedButIncluded() { - const unusedConst = 'unused'; - if (true) { - true ? 'first' : 'second'; - } else { - (true && 'first') || 'second'; - } - 'sequence', 'expression'; - switch ('test') { - case 'test': - (() => {})(); - case 'other': - 'no effect'; - default: - const ignored = 2; - } - } - - function test( - unusedParam = { - prop: function test() { - var unused = 1; - } - } - ) {} - - test({ - prop: function test() { - var unused = 1; - } - }); - - try { - const x = 1; - } catch {} - - exports.create = create; - exports.getPrototypeOf = getPrototypeOf; - exports.quux = quux; - exports.strange = quux; - - return exports; - -}({}, external)); diff --git a/test/form/samples/no-treeshake/_expected/system.js b/test/form/samples/no-treeshake/_expected/system.js deleted file mode 100644 index e367cf088b2..00000000000 --- a/test/form/samples/no-treeshake/_expected/system.js +++ /dev/null @@ -1,61 +0,0 @@ -System.register('stirred', ['external'], function (exports) { - 'use strict'; - var value; - return { - setters: [function (module) { - value = module.value; - }], - execute: function () { - - var foo = 13; - - const quux = function (v) { return exports({ strange: v, quux: v }), v; }(1); - - const other = () => quux; - - function baz() { - return foo + value; - } - - var create = exports('create', Object.create), - getPrototypeOf = exports('getPrototypeOf', Object.getPrototypeOf); - - function unusedButIncluded() { - const unusedConst = 'unused'; - if (true) { - true ? 'first' : 'second'; - } else { - (true && 'first') || 'second'; - } - 'sequence', 'expression'; - switch ('test') { - case 'test': - (() => {})(); - case 'other': - 'no effect'; - default: - const ignored = 2; - } - } - - function test( - unusedParam = { - prop: function test() { - var unused = 1; - } - } - ) {} - - test({ - prop: function test() { - var unused = 1; - } - }); - - try { - const x = 1; - } catch {} - - } - }; -}); diff --git a/test/form/samples/no-treeshake/_expected/umd.js b/test/form/samples/no-treeshake/_expected/umd.js deleted file mode 100644 index 0b6730ab099..00000000000 --- a/test/form/samples/no-treeshake/_expected/umd.js +++ /dev/null @@ -1,63 +0,0 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('external')) : - typeof define === 'function' && define.amd ? define(['exports', 'external'], factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.stirred = {}, global.external)); -}(this, (function (exports, external) { 'use strict'; - - var foo = 13; - - const quux = 1; - - const other = () => quux; - - function baz() { - return foo + external.value; - } - - var create = Object.create, - getPrototypeOf = Object.getPrototypeOf; - - function unusedButIncluded() { - const unusedConst = 'unused'; - if (true) { - true ? 'first' : 'second'; - } else { - (true && 'first') || 'second'; - } - 'sequence', 'expression'; - switch ('test') { - case 'test': - (() => {})(); - case 'other': - 'no effect'; - default: - const ignored = 2; - } - } - - function test( - unusedParam = { - prop: function test() { - var unused = 1; - } - } - ) {} - - test({ - prop: function test() { - var unused = 1; - } - }); - - try { - const x = 1; - } catch {} - - exports.create = create; - exports.getPrototypeOf = getPrototypeOf; - exports.quux = quux; - exports.strange = quux; - - Object.defineProperty(exports, '__esModule', { value: true }); - -}))); diff --git a/test/form/samples/no-treeshake/main.js b/test/form/samples/no-treeshake/main.js index 47ab0fff75a..2dde2e93fa0 100644 --- a/test/form/samples/no-treeshake/main.js +++ b/test/form/samples/no-treeshake/main.js @@ -18,6 +18,11 @@ function unusedButIncluded() { } else { (true && 'first') || 'second'; } + if (false) { + 'first'; + } else { + 'second'; + } 'sequence', 'expression'; switch ('test') { case 'test': diff --git a/test/form/samples/redeclarations/_expected.js b/test/form/samples/redeclarations/_expected.js new file mode 100644 index 00000000000..b50a7e95467 --- /dev/null +++ b/test/form/samples/redeclarations/_expected.js @@ -0,0 +1,8 @@ +var foo = () => {}; + +while ( true ) { + var foo = () => console.log( 'effect' ); + break; +} + +foo(); diff --git a/test/form/samples/redeclarations/_expected/amd.js b/test/form/samples/redeclarations/_expected/amd.js deleted file mode 100644 index 728b2ca9b02..00000000000 --- a/test/form/samples/redeclarations/_expected/amd.js +++ /dev/null @@ -1,24 +0,0 @@ -define(function () { 'use strict'; - - var foo = () => {}; - - while ( true ) { - var foo = () => console.log( 'effect' ); - break; - } - - foo(); - - function baz () {} - - while ( true ) { - function baz () { - console.log( 'effect' ); - } - - break; - } - - baz(); - -}); diff --git a/test/form/samples/redeclarations/_expected/cjs.js b/test/form/samples/redeclarations/_expected/cjs.js deleted file mode 100644 index 323cd6db1f1..00000000000 --- a/test/form/samples/redeclarations/_expected/cjs.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -var foo = () => {}; - -while ( true ) { - var foo = () => console.log( 'effect' ); - break; -} - -foo(); - -function baz () {} - -while ( true ) { - function baz () { - console.log( 'effect' ); - } - - break; -} - -baz(); diff --git a/test/form/samples/redeclarations/_expected/es.js b/test/form/samples/redeclarations/_expected/es.js deleted file mode 100644 index 92b04225694..00000000000 --- a/test/form/samples/redeclarations/_expected/es.js +++ /dev/null @@ -1,20 +0,0 @@ -var foo = () => {}; - -while ( true ) { - var foo = () => console.log( 'effect' ); - break; -} - -foo(); - -function baz () {} - -while ( true ) { - function baz () { - console.log( 'effect' ); - } - - break; -} - -baz(); diff --git a/test/form/samples/redeclarations/_expected/iife.js b/test/form/samples/redeclarations/_expected/iife.js deleted file mode 100644 index 0eb0942c9b1..00000000000 --- a/test/form/samples/redeclarations/_expected/iife.js +++ /dev/null @@ -1,25 +0,0 @@ -(function () { - 'use strict'; - - var foo = () => {}; - - while ( true ) { - var foo = () => console.log( 'effect' ); - break; - } - - foo(); - - function baz () {} - - while ( true ) { - function baz () { - console.log( 'effect' ); - } - - break; - } - - baz(); - -}()); diff --git a/test/form/samples/redeclarations/_expected/system.js b/test/form/samples/redeclarations/_expected/system.js deleted file mode 100644 index 0f707b66b62..00000000000 --- a/test/form/samples/redeclarations/_expected/system.js +++ /dev/null @@ -1,29 +0,0 @@ -System.register([], function () { - 'use strict'; - return { - execute: function () { - - var foo = () => {}; - - while ( true ) { - var foo = () => console.log( 'effect' ); - break; - } - - foo(); - - function baz () {} - - while ( true ) { - function baz () { - console.log( 'effect' ); - } - - break; - } - - baz(); - - } - }; -}); diff --git a/test/form/samples/redeclarations/_expected/umd.js b/test/form/samples/redeclarations/_expected/umd.js deleted file mode 100644 index b822502568c..00000000000 --- a/test/form/samples/redeclarations/_expected/umd.js +++ /dev/null @@ -1,27 +0,0 @@ -(function (factory) { - typeof define === 'function' && define.amd ? define(factory) : - factory(); -}((function () { 'use strict'; - - var foo = () => {}; - - while ( true ) { - var foo = () => console.log( 'effect' ); - break; - } - - foo(); - - function baz () {} - - while ( true ) { - function baz () { - console.log( 'effect' ); - } - - break; - } - - baz(); - -}))); diff --git a/test/form/samples/redeclarations/main.js b/test/form/samples/redeclarations/main.js index 14f10446a0e..5c24aa381ba 100644 --- a/test/form/samples/redeclarations/main.js +++ b/test/form/samples/redeclarations/main.js @@ -19,6 +19,7 @@ bar(); function baz () {} while ( true ) { + // in strict mode, this is not a redeclaration function baz () { console.log( 'effect' ); } diff --git a/test/form/samples/tree-shake-if-statements/_expected/es.js b/test/form/samples/tree-shake-if-statements/_expected.js similarity index 57% rename from test/form/samples/tree-shake-if-statements/_expected/es.js rename to test/form/samples/tree-shake-if-statements/_expected.js index e99bc3e70e1..d4a9358638d 100644 --- a/test/form/samples/tree-shake-if-statements/_expected/es.js +++ b/test/form/samples/tree-shake-if-statements/_expected.js @@ -8,21 +8,15 @@ if (console.log(1) || unknown) ; console.log('kept'); } -if (true) { +var a; { console.log('kept'); -} else { - var a; - function b() {} } -console.log(typeof a, typeof b); +console.log(a); -if (true) { +var b; { console.log('kept'); -} else { - var a; - function b() {} } -console.log(typeof a, typeof b); +console.log(b); if (console.log('effect'), true) { console.log('kept'); @@ -36,19 +30,13 @@ if (console.log('effect'), true) { console.log('kept'); } -if (false) { - var c; - function d() {} -} -console.log(typeof c, typeof d); +var c; +console.log(c); -if (false) { - var e; - function f() {} -} else { +var d; { console.log('kept'); } -console.log(typeof e, typeof f); +console.log(d); if (console.log('effect'), false) ; diff --git a/test/form/samples/tree-shake-if-statements/_expected/amd.js b/test/form/samples/tree-shake-if-statements/_expected/amd.js deleted file mode 100644 index cdc14ba8cc5..00000000000 --- a/test/form/samples/tree-shake-if-statements/_expected/amd.js +++ /dev/null @@ -1,61 +0,0 @@ -define(function () { 'use strict'; - - if (console.log(1) || unknown) ; - - { - console.log('kept'); - } - - { - console.log('kept'); - } - - if (true) { - console.log('kept'); - } else { - var a; - function b() {} - } - console.log(typeof a, typeof b); - - if (true) { - console.log('kept'); - } else { - var a; - function b() {} - } - console.log(typeof a, typeof b); - - if (console.log('effect'), true) { - console.log('kept'); - } - - if (console.log('effect'), true) { - console.log('kept'); - } - - { - console.log('kept'); - } - - if (false) { - var c; - function d() {} - } - console.log(typeof c, typeof d); - - if (false) { - var e; - function f() {} - } else { - console.log('kept'); - } - console.log(typeof e, typeof f); - - if (console.log('effect'), false) ; - - if (console.log('effect'), false) ; else { - console.log('kept'); - } - -}); diff --git a/test/form/samples/tree-shake-if-statements/_expected/cjs.js b/test/form/samples/tree-shake-if-statements/_expected/cjs.js deleted file mode 100644 index 317b974ae97..00000000000 --- a/test/form/samples/tree-shake-if-statements/_expected/cjs.js +++ /dev/null @@ -1,59 +0,0 @@ -'use strict'; - -if (console.log(1) || unknown) ; - -{ - console.log('kept'); -} - -{ - console.log('kept'); -} - -if (true) { - console.log('kept'); -} else { - var a; - function b() {} -} -console.log(typeof a, typeof b); - -if (true) { - console.log('kept'); -} else { - var a; - function b() {} -} -console.log(typeof a, typeof b); - -if (console.log('effect'), true) { - console.log('kept'); -} - -if (console.log('effect'), true) { - console.log('kept'); -} - -{ - console.log('kept'); -} - -if (false) { - var c; - function d() {} -} -console.log(typeof c, typeof d); - -if (false) { - var e; - function f() {} -} else { - console.log('kept'); -} -console.log(typeof e, typeof f); - -if (console.log('effect'), false) ; - -if (console.log('effect'), false) ; else { - console.log('kept'); -} diff --git a/test/form/samples/tree-shake-if-statements/_expected/iife.js b/test/form/samples/tree-shake-if-statements/_expected/iife.js deleted file mode 100644 index 23536f10a57..00000000000 --- a/test/form/samples/tree-shake-if-statements/_expected/iife.js +++ /dev/null @@ -1,62 +0,0 @@ -(function () { - 'use strict'; - - if (console.log(1) || unknown) ; - - { - console.log('kept'); - } - - { - console.log('kept'); - } - - if (true) { - console.log('kept'); - } else { - var a; - function b() {} - } - console.log(typeof a, typeof b); - - if (true) { - console.log('kept'); - } else { - var a; - function b() {} - } - console.log(typeof a, typeof b); - - if (console.log('effect'), true) { - console.log('kept'); - } - - if (console.log('effect'), true) { - console.log('kept'); - } - - { - console.log('kept'); - } - - if (false) { - var c; - function d() {} - } - console.log(typeof c, typeof d); - - if (false) { - var e; - function f() {} - } else { - console.log('kept'); - } - console.log(typeof e, typeof f); - - if (console.log('effect'), false) ; - - if (console.log('effect'), false) ; else { - console.log('kept'); - } - -}()); diff --git a/test/form/samples/tree-shake-if-statements/_expected/system.js b/test/form/samples/tree-shake-if-statements/_expected/system.js deleted file mode 100644 index f1ee48b7a6d..00000000000 --- a/test/form/samples/tree-shake-if-statements/_expected/system.js +++ /dev/null @@ -1,66 +0,0 @@ -System.register([], function () { - 'use strict'; - return { - execute: function () { - - if (console.log(1) || unknown) ; - - { - console.log('kept'); - } - - { - console.log('kept'); - } - - if (true) { - console.log('kept'); - } else { - var a; - function b() {} - } - console.log(typeof a, typeof b); - - if (true) { - console.log('kept'); - } else { - var a; - function b() {} - } - console.log(typeof a, typeof b); - - if (console.log('effect'), true) { - console.log('kept'); - } - - if (console.log('effect'), true) { - console.log('kept'); - } - - { - console.log('kept'); - } - - if (false) { - var c; - function d() {} - } - console.log(typeof c, typeof d); - - if (false) { - var e; - function f() {} - } else { - console.log('kept'); - } - console.log(typeof e, typeof f); - - if (console.log('effect'), false) ; - - if (console.log('effect'), false) ; else { - console.log('kept'); - } - - } - }; -}); diff --git a/test/form/samples/tree-shake-if-statements/_expected/umd.js b/test/form/samples/tree-shake-if-statements/_expected/umd.js deleted file mode 100644 index 620ca62923f..00000000000 --- a/test/form/samples/tree-shake-if-statements/_expected/umd.js +++ /dev/null @@ -1,64 +0,0 @@ -(function (factory) { - typeof define === 'function' && define.amd ? define(factory) : - factory(); -}((function () { 'use strict'; - - if (console.log(1) || unknown) ; - - { - console.log('kept'); - } - - { - console.log('kept'); - } - - if (true) { - console.log('kept'); - } else { - var a; - function b() {} - } - console.log(typeof a, typeof b); - - if (true) { - console.log('kept'); - } else { - var a; - function b() {} - } - console.log(typeof a, typeof b); - - if (console.log('effect'), true) { - console.log('kept'); - } - - if (console.log('effect'), true) { - console.log('kept'); - } - - { - console.log('kept'); - } - - if (false) { - var c; - function d() {} - } - console.log(typeof c, typeof d); - - if (false) { - var e; - function f() {} - } else { - console.log('kept'); - } - console.log(typeof e, typeof f); - - if (console.log('effect'), false) ; - - if (console.log('effect'), false) ; else { - console.log('kept'); - } - -}))); diff --git a/test/form/samples/tree-shake-if-statements/main.js b/test/form/samples/tree-shake-if-statements/main.js index 68e5fcefd44..2ade7ee25bf 100644 --- a/test/form/samples/tree-shake-if-statements/main.js +++ b/test/form/samples/tree-shake-if-statements/main.js @@ -19,9 +19,8 @@ if (true) { } else { console.log('removed'); var a; - function b() {} } -console.log(typeof a, typeof b); +console.log(a); function noEffect(){} @@ -29,10 +28,9 @@ if (noEffect(), true) { console.log('kept'); } else { console.log('removed'); - var a; - function b() {} + var b; } -console.log(typeof a, typeof b); +console.log(b); if (console.log('effect'), true) { console.log('kept'); @@ -58,18 +56,16 @@ if (false) { if (false) { console.log('removed'); var c; - function d() {} } -console.log(typeof c, typeof d); +console.log(c); if (false) { console.log('removed'); - var e; - function f() {} + var d; } else { console.log('kept'); } -console.log(typeof e, typeof f); +console.log(d); if (console.log('effect'), false) { console.log('removed');