diff --git a/src/ast/nodes/ArrayExpression.ts b/src/ast/nodes/ArrayExpression.ts index 9b9ce995d53..67710bc8f13 100644 --- a/src/ast/nodes/ArrayExpression.ts +++ b/src/ast/nodes/ArrayExpression.ts @@ -85,11 +85,7 @@ export default class ArrayExpression extends NodeBase { if (element) { if (hasSpread || element instanceof SpreadElement) { hasSpread = true; - // This also deoptimizes parameter defaults element.deoptimizePath(UNKNOWN_PATH); - } else { - // We do not track parameter defaults in arrays - element.deoptimizeCallParameters(); } } } diff --git a/src/ast/nodes/ArrowFunctionExpression.ts b/src/ast/nodes/ArrowFunctionExpression.ts index 16095f924e3..cb294d859e1 100644 --- a/src/ast/nodes/ArrowFunctionExpression.ts +++ b/src/ast/nodes/ArrowFunctionExpression.ts @@ -1,12 +1,13 @@ import { type CallOptions } from '../CallOptions'; -import { type HasEffectsContext } from '../ExecutionContext'; +import { type HasEffectsContext, InclusionContext } from '../ExecutionContext'; import ReturnValueScope from '../scopes/ReturnValueScope'; import type Scope from '../scopes/Scope'; import { type ObjectPath } from '../utils/PathTracker'; import BlockStatement from './BlockStatement'; +import Identifier from './Identifier'; import * as NodeType from './NodeType'; import FunctionBase from './shared/FunctionBase'; -import { type ExpressionNode } from './shared/Node'; +import { type ExpressionNode, IncludeChildren } from './shared/Node'; import { ObjectEntity } from './shared/ObjectEntity'; import { OBJECT_PROTOTYPE } from './shared/ObjectPrototype'; import type { PatternNode } from './shared/Pattern'; @@ -48,6 +49,15 @@ export default class ArrowFunctionExpression extends FunctionBase { return false; } + include(context: InclusionContext, includeChildrenRecursively: IncludeChildren): void { + super.include(context, includeChildrenRecursively); + for (const param of this.params) { + if (!(param instanceof Identifier)) { + param.include(context, includeChildrenRecursively); + } + } + } + protected getObjectEntity(): ObjectEntity { if (this.objectEntity !== null) { return this.objectEntity; diff --git a/src/ast/nodes/AssignmentPattern.ts b/src/ast/nodes/AssignmentPattern.ts index 08e0b799910..f0238ae0fb7 100644 --- a/src/ast/nodes/AssignmentPattern.ts +++ b/src/ast/nodes/AssignmentPattern.ts @@ -35,10 +35,8 @@ export default class AssignmentPattern extends NodeBase implements PatternNode { return path.length > 0 || this.left.hasEffectsWhenAssignedAtPath(EMPTY_PATH, context); } - // Note that FunctionBase may directly include .left and .right without - // including the pattern itself. This is how default parameter tree-shaking - // works at the moment. include(context: InclusionContext, includeChildrenRecursively: IncludeChildren): void { + if (!this.deoptimized) this.applyDeoptimizations(); this.included = true; this.left.include(context, includeChildrenRecursively); this.right.include(context, includeChildrenRecursively); diff --git a/src/ast/nodes/CallExpression.ts b/src/ast/nodes/CallExpression.ts index 5f55a0b4f9d..2b6f84f234a 100644 --- a/src/ast/nodes/CallExpression.ts +++ b/src/ast/nodes/CallExpression.ts @@ -95,7 +95,7 @@ export default class CallExpression extends CallExpressionBase implements Deopti } } else { this.included = true; - this.callee.include(context, false, { includeWithoutParameterDefaults: true }); + this.callee.include(context, false); } this.callee.includeCallArguments(context, this.arguments); const returnExpression = this.getReturnExpression(); diff --git a/src/ast/nodes/FunctionDeclaration.ts b/src/ast/nodes/FunctionDeclaration.ts index adcad843f41..ddf88636455 100644 --- a/src/ast/nodes/FunctionDeclaration.ts +++ b/src/ast/nodes/FunctionDeclaration.ts @@ -1,17 +1,12 @@ -import { InclusionContext } from '../ExecutionContext'; import type ChildScope from '../scopes/ChildScope'; import Identifier, { type IdentifierWithVariable } from './Identifier'; import type * as NodeType from './NodeType'; import FunctionNode from './shared/FunctionNode'; -import type { GenericEsTreeNode, IncludeChildren } from './shared/Node'; +import type { GenericEsTreeNode } from './shared/Node'; export default class FunctionDeclaration extends FunctionNode { declare type: NodeType.tFunctionDeclaration; - include(context: InclusionContext, includeChildrenRecursively: IncludeChildren) { - super.include(context, includeChildrenRecursively, { includeWithoutParameterDefaults: true }); - } - initialise(): void { super.initialise(); if (this.id !== null) { diff --git a/src/ast/nodes/Identifier.ts b/src/ast/nodes/Identifier.ts index 2ce3511a769..03125e097ce 100644 --- a/src/ast/nodes/Identifier.ts +++ b/src/ast/nodes/Identifier.ts @@ -86,10 +86,6 @@ export default class Identifier extends NodeBase implements PatternNode { return [(this.variable = variable)]; } - deoptimizeCallParameters() { - this.variable!.deoptimizeCallParameters(); - } - deoptimizePath(path: ObjectPath): void { if (path.length === 0 && !this.scope.contains(this.name)) { this.disallowImportReassignment(); diff --git a/src/ast/nodes/ObjectExpression.ts b/src/ast/nodes/ObjectExpression.ts index 034281064e7..8f956916205 100644 --- a/src/ast/nodes/ObjectExpression.ts +++ b/src/ast/nodes/ObjectExpression.ts @@ -102,14 +102,7 @@ export default class ObjectExpression extends NodeBase implements DeoptimizableE } } - protected applyDeoptimizations() { - this.deoptimized = true; - for (const property of this.properties) { - if (property instanceof Property) { - property.value.deoptimizeCallParameters(); - } - } - } + protected applyDeoptimizations() {} private getObjectEntity(): ObjectEntity { if (this.objectEntity !== null) { diff --git a/src/ast/nodes/VariableDeclarator.ts b/src/ast/nodes/VariableDeclarator.ts index f1e7c654928..2ffef75cd92 100644 --- a/src/ast/nodes/VariableDeclarator.ts +++ b/src/ast/nodes/VariableDeclarator.ts @@ -35,9 +35,7 @@ export default class VariableDeclarator extends NodeBase { include(context: InclusionContext, includeChildrenRecursively: IncludeChildren): void { this.included = true; - this.init?.include(context, includeChildrenRecursively, { - includeWithoutParameterDefaults: true - }); + this.init?.include(context, includeChildrenRecursively); this.id.markDeclarationReached(); if (includeChildrenRecursively || this.id.shouldBeIncluded(context)) { this.id.include(context, includeChildrenRecursively); diff --git a/src/ast/nodes/YieldExpression.ts b/src/ast/nodes/YieldExpression.ts index f92c01026e0..cc44e8ea1e0 100644 --- a/src/ast/nodes/YieldExpression.ts +++ b/src/ast/nodes/YieldExpression.ts @@ -11,7 +11,7 @@ export default class YieldExpression extends NodeBase { hasEffects(context: HasEffectsContext): boolean { if (!this.deoptimized) this.applyDeoptimizations(); - return !context.ignore.returnYield || !!this.argument?.hasEffects(context); + return !(context.ignore.returnYield && !this.argument?.hasEffects(context)); } render(code: MagicString, options: RenderOptions): void { diff --git a/src/ast/nodes/shared/ClassNode.ts b/src/ast/nodes/shared/ClassNode.ts index 249ea7cf378..5a6ee0e81dd 100644 --- a/src/ast/nodes/shared/ClassNode.ts +++ b/src/ast/nodes/shared/ClassNode.ts @@ -16,7 +16,6 @@ import type ClassBody from '../ClassBody'; import Identifier from '../Identifier'; import type Literal from '../Literal'; import MethodDefinition from '../MethodDefinition'; -import PropertyDefinition from '../PropertyDefinition'; import { type ExpressionEntity, type LiteralValueOrUnknown } from './Expression'; import { type ExpressionNode, type IncludeChildren, NodeBase } from './Node'; import { ObjectEntity, type ObjectProperty } from './ObjectEntity'; @@ -40,12 +39,6 @@ export default class ClassNode extends NodeBase implements DeoptimizableEntity { deoptimizePath(path: ObjectPath): void { this.getObjectEntity().deoptimizePath(path); - if (path.length === 1 && path[0] === UnknownKey) { - // A reassignment of UNKNOWN_PATH is considered equivalent to having lost track - // which means the constructor needs to be reassigned - this.classConstructor?.deoptimizePath(UNKNOWN_PATH); - this.superClass?.deoptimizePath(UNKNOWN_PATH); - } } deoptimizeThisOnEventAtPath( @@ -150,11 +143,8 @@ export default class ClassNode extends NodeBase implements DeoptimizableEntity { ) { // Calls to methods are not tracked, ensure that the return value is deoptimized definition.deoptimizePath(UNKNOWN_PATH); - } else if (definition instanceof PropertyDefinition) { - definition.value?.deoptimizeCallParameters(); } } - this.superClass?.deoptimizeCallParameters(); this.context.requestTreeshakingPass(); } diff --git a/src/ast/nodes/shared/Expression.ts b/src/ast/nodes/shared/Expression.ts index c231d4c2402..a28e47dd769 100644 --- a/src/ast/nodes/shared/Expression.ts +++ b/src/ast/nodes/shared/Expression.ts @@ -18,14 +18,11 @@ export interface InclusionOptions { * Include the id of a declarator even if unused to ensure it is a valid statement. */ asSingleStatement?: boolean; - includeWithoutParameterDefaults?: boolean; } export class ExpressionEntity implements WritableEntity { included = false; - deoptimizeCallParameters(): void {} - deoptimizePath(_path: ObjectPath): void {} deoptimizeThisOnEventAtPath( diff --git a/src/ast/nodes/shared/FunctionBase.ts b/src/ast/nodes/shared/FunctionBase.ts index 6bf3f80c5bb..05d09d3ac47 100644 --- a/src/ast/nodes/shared/FunctionBase.ts +++ b/src/ast/nodes/shared/FunctionBase.ts @@ -1,5 +1,4 @@ import type { NormalizedTreeshakingOptions } from '../../../rollup/types'; -import { BLANK } from '../../../utils/blank'; import { type CallOptions, NO_ARGS } from '../../CallOptions'; import { DeoptimizableEntity } from '../../DeoptimizableEntity'; import { @@ -9,27 +8,12 @@ import { } from '../../ExecutionContext'; import { NodeEvent } from '../../NodeEvents'; import ReturnValueScope from '../../scopes/ReturnValueScope'; -import { - EMPTY_PATH, - type ObjectPath, - PathTracker, - SHARED_RECURSION_TRACKER, - UNKNOWN_PATH, - UnknownKey -} from '../../utils/PathTracker'; -import LocalVariable from '../../variables/LocalVariable'; -import AssignmentPattern from '../AssignmentPattern'; +import { type ObjectPath, PathTracker, UNKNOWN_PATH, UnknownKey } from '../../utils/PathTracker'; import BlockStatement from '../BlockStatement'; import * as NodeType from '../NodeType'; import RestElement from '../RestElement'; import type SpreadElement from '../SpreadElement'; -import { - type ExpressionEntity, - InclusionOptions, - LiteralValueOrUnknown, - UNKNOWN_EXPRESSION, - UnknownValue -} from './Expression'; +import { type ExpressionEntity, LiteralValueOrUnknown, UNKNOWN_EXPRESSION } from './Expression'; import { type ExpressionNode, type GenericEsTreeNode, @@ -39,7 +23,7 @@ import { import { ObjectEntity } from './ObjectEntity'; import type { PatternNode } from './Pattern'; -export default abstract class FunctionBase extends NodeBase implements DeoptimizableEntity { +export default abstract class FunctionBase extends NodeBase { declare async: boolean; declare body: BlockStatement | ExpressionNode; declare params: readonly PatternNode[]; @@ -47,23 +31,12 @@ export default abstract class FunctionBase extends NodeBase implements Deoptimiz declare scope: ReturnValueScope; protected objectEntity: ObjectEntity | null = null; private deoptimizedReturn = false; - private forceIncludeParameters = false; - private declare parameterVariables: LocalVariable[][]; - - deoptimizeCache() { - this.forceIncludeParameters = true; - } - - deoptimizeCallParameters() { - this.forceIncludeParameters = true; - } deoptimizePath(path: ObjectPath): void { this.getObjectEntity().deoptimizePath(path); if (path.length === 1 && path[0] === UnknownKey) { // A reassignment of UNKNOWN_PATH is considered equivalent to having lost track // which means the return expression needs to be reassigned - this.forceIncludeParameters = true; this.scope.getReturnExpression().deoptimizePath(UNKNOWN_PATH); } } @@ -150,89 +123,31 @@ export default abstract class FunctionBase extends NodeBase implements Deoptimiz return true; } } - for (let position = 0; position < this.params.length; position++) { - const parameter = this.params[position]; - if (parameter instanceof AssignmentPattern) { - if (parameter.left.hasEffects(context)) { - return true; - } - const argumentValue = callOptions.args[position]?.getLiteralValueAtPath( - EMPTY_PATH, - SHARED_RECURSION_TRACKER, - this - ); - if ( - (argumentValue === undefined || argumentValue === UnknownValue) && - parameter.right.hasEffects(context) - ) { - return true; - } - } else if (parameter.hasEffects(context)) { - return true; - } + for (const param of this.params) { + if (param.hasEffects(context)) return true; } return false; } - include( - context: InclusionContext, - includeChildrenRecursively: IncludeChildren, - { includeWithoutParameterDefaults }: InclusionOptions = BLANK - ): void { + include(context: InclusionContext, includeChildrenRecursively: IncludeChildren): void { if (!this.deoptimized) this.applyDeoptimizations(); this.included = true; const { brokenFlow } = context; context.brokenFlow = BROKEN_FLOW_NONE; this.body.include(context, includeChildrenRecursively); context.brokenFlow = brokenFlow; - if ( - !includeWithoutParameterDefaults || - includeChildrenRecursively || - this.forceIncludeParameters - ) { - for (const param of this.params) { - param.include(context, includeChildrenRecursively); - } - } } includeCallArguments( context: InclusionContext, args: readonly (ExpressionEntity | SpreadElement)[] ): void { - for (let position = 0; position < this.params.length; position++) { - const parameter = this.params[position]; - if (parameter instanceof AssignmentPattern) { - if (parameter.left.shouldBeIncluded(context)) { - parameter.left.include(context, false); - } - const argumentValue = args[position]?.getLiteralValueAtPath( - EMPTY_PATH, - SHARED_RECURSION_TRACKER, - this - ); - // If argumentValue === UnknownTruthyValue, then we do not need to - // include the default - if ( - (argumentValue === undefined || argumentValue === UnknownValue) && - (this.parameterVariables[position].some(variable => variable.included) || - parameter.right.shouldBeIncluded(context)) - ) { - parameter.right.include(context, false); - } - } else if (parameter.shouldBeIncluded(context)) { - parameter.include(context, false); - } - } this.scope.includeCallArguments(context, args); } initialise(): void { - this.parameterVariables = this.params.map(param => - param.declare('parameter', UNKNOWN_EXPRESSION) - ); this.scope.addParameterVariables( - this.parameterVariables, + this.params.map(param => param.declare('parameter', UNKNOWN_EXPRESSION)), this.params[this.params.length - 1] instanceof RestElement ); if (this.body instanceof BlockStatement) { @@ -249,15 +164,7 @@ export default abstract class FunctionBase extends NodeBase implements Deoptimiz super.parseNode(esTreeNode); } - protected applyDeoptimizations() { - // We currently do not track deoptimizations of default values, deoptimize them - // just as we deoptimize call arguments - for (const param of this.params) { - if (param instanceof AssignmentPattern) { - param.right.deoptimizePath(UNKNOWN_PATH); - } - } - } + protected applyDeoptimizations() {} protected abstract getObjectEntity(): ObjectEntity; } diff --git a/src/ast/nodes/shared/FunctionNode.ts b/src/ast/nodes/shared/FunctionNode.ts index 11b0b99314d..95867d14844 100644 --- a/src/ast/nodes/shared/FunctionNode.ts +++ b/src/ast/nodes/shared/FunctionNode.ts @@ -1,12 +1,11 @@ -import { BLANK } from '../../../utils/blank'; import { type CallOptions } from '../../CallOptions'; import { type HasEffectsContext, type InclusionContext } from '../../ExecutionContext'; import { EVENT_CALLED, type NodeEvent } from '../../NodeEvents'; import FunctionScope from '../../scopes/FunctionScope'; import { type ObjectPath, PathTracker } from '../../utils/PathTracker'; import BlockStatement from '../BlockStatement'; -import { type IdentifierWithVariable } from '../Identifier'; -import { type ExpressionEntity, InclusionOptions, UNKNOWN_EXPRESSION } from './Expression'; +import Identifier, { type IdentifierWithVariable } from '../Identifier'; +import { type ExpressionEntity, UNKNOWN_EXPRESSION } from './Expression'; import FunctionBase from './FunctionBase'; import { type IncludeChildren } from './Node'; import { ObjectEntity } from './ObjectEntity'; @@ -74,16 +73,15 @@ export default class FunctionNode extends FunctionBase { return false; } - include( - context: InclusionContext, - includeChildrenRecursively: IncludeChildren, - { includeWithoutParameterDefaults }: InclusionOptions = BLANK - ): void { + include(context: InclusionContext, includeChildrenRecursively: IncludeChildren): void { + super.include(context, includeChildrenRecursively); this.id?.include(); - super.include(context, includeChildrenRecursively, { - includeWithoutParameterDefaults: - includeWithoutParameterDefaults && !this.scope.argumentsVariable.included - }); + const hasArguments = this.scope.argumentsVariable.included; + for (const param of this.params) { + if (!(param instanceof Identifier) || hasArguments) { + param.include(context, includeChildrenRecursively); + } + } } initialise(): void { diff --git a/src/ast/variables/LocalVariable.ts b/src/ast/variables/LocalVariable.ts index bb6e4c3f41b..e585ea775a3 100644 --- a/src/ast/variables/LocalVariable.ts +++ b/src/ast/variables/LocalVariable.ts @@ -59,10 +59,6 @@ export default class LocalVariable extends Variable { } } - deoptimizeCallParameters() { - this.init?.deoptimizeCallParameters(); - } - deoptimizePath(path: ObjectPath): void { if ( this.isReassigned || diff --git a/test/cli/samples/plugin/basic/_expected.js b/test/cli/samples/plugin/basic/_expected.js index e83de861ed5..c6d4a07ef77 100644 --- a/test/cli/samples/plugin/basic/_expected.js +++ b/test/cli/samples/plugin/basic/_expected.js @@ -2,7 +2,7 @@ Object.defineProperty(exports, '__esModule', { value: true }); -var Bar = function Bar(x) { +var Bar = function Bar(value) { this.x = value; }; Bar.prototype.value = function value () { diff --git a/test/cli/samples/plugin/basic/main.js b/test/cli/samples/plugin/basic/main.js index 49486331fe7..a42c7cc4c5c 100644 --- a/test/cli/samples/plugin/basic/main.js +++ b/test/cli/samples/plugin/basic/main.js @@ -1,5 +1,5 @@ export class Bar { - constructor(x) { + constructor(value) { this.x = value; } value() { diff --git a/test/form/samples/parameter-defaults/default-parameter-side-effects/_config.js b/test/form/samples/parameter-defaults/default-parameter-side-effects/_config.js deleted file mode 100644 index 7a232d2ace8..00000000000 --- a/test/form/samples/parameter-defaults/default-parameter-side-effects/_config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - description: 'handles side effects of default parameters' -}; diff --git a/test/form/samples/parameter-defaults/default-parameter-side-effects/_expected.js b/test/form/samples/parameter-defaults/default-parameter-side-effects/_expected.js deleted file mode 100644 index d5e814ca54a..00000000000 --- a/test/form/samples/parameter-defaults/default-parameter-side-effects/_expected.js +++ /dev/null @@ -1,17 +0,0 @@ -const a = (p = 'retained') => console.log(p); -a(); - -const b = (p) => console.log(p); -b('value'); - -const c = (p = console.log('retained because of side effect')) => {}; -c(); - -const d = (p) => console.log('effect'); -d(); - -const e = (p) => console.log('effect'); -e(); - -const f = ({ x = console.log('retained') }) => {}; -f('value'); diff --git a/test/form/samples/parameter-defaults/default-parameter-side-effects/main.js b/test/form/samples/parameter-defaults/default-parameter-side-effects/main.js deleted file mode 100644 index bc551eb69bc..00000000000 --- a/test/form/samples/parameter-defaults/default-parameter-side-effects/main.js +++ /dev/null @@ -1,20 +0,0 @@ -const a = (p = 'retained') => console.log(p); -a(); - -const b = (p = console.log('removed')) => console.log(p); -b('value'); - -const c = (p = console.log('retained because of side effect')) => {}; -c(); - -const d = (p = 'removed because no side effect') => console.log('effect'); -d(); - -const e = (p = console.log('removed')) => console.log('effect'); -e('value'); - -const f = ({ x = console.log('retained') } = {}) => {}; -f('value'); - -const removed = (p = console.log('ignored')) => {}; -removed('value'); diff --git a/test/form/samples/parameter-defaults/functions/_config.js b/test/form/samples/parameter-defaults/functions/_config.js deleted file mode 100644 index 0faee52a9f7..00000000000 --- a/test/form/samples/parameter-defaults/functions/_config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - description: 'supports tree-shaking for unused default parameter values for functions' -}; diff --git a/test/form/samples/parameter-defaults/functions/_expected.js b/test/form/samples/parameter-defaults/functions/_expected.js deleted file mode 100644 index 945aec4a8bc..00000000000 --- a/test/form/samples/parameter-defaults/functions/_expected.js +++ /dev/null @@ -1,21 +0,0 @@ -var isUndefined; - -function funDecl(a = 'retained', b = 'retained', c, d) { - console.log(a, b, c); -} - -funDecl(isUndefined, 'b', 'c'); -funDecl('a', globalThis.unknown, 'c'); - -const funExp = function (a = 'retained', b = 'retained', c, d) { - console.log(a, b, c); -}; - -funExp(isUndefined, 'b', 'c'); -funExp('a', globalThis.unknown, 'c'); - -const arrow = (a = 'retained', b = 'retained', c, d) => - console.log(a, b, c); - -arrow(isUndefined, 'b', 'c'); -arrow('a', globalThis.unknown, 'c'); diff --git a/test/form/samples/parameter-defaults/functions/main.js b/test/form/samples/parameter-defaults/functions/main.js deleted file mode 100644 index 048cf4dbae2..00000000000 --- a/test/form/samples/parameter-defaults/functions/main.js +++ /dev/null @@ -1,21 +0,0 @@ -var isUndefined; - -function funDecl(a = 'retained', b = 'retained', c = 'removed', d = 'removed') { - console.log(a, b, c); -} - -funDecl(isUndefined, 'b', 'c'); -funDecl('a', globalThis.unknown, 'c'); - -const funExp = function (a = 'retained', b = 'retained', c = 'removed', d = 'removed') { - console.log(a, b, c); -}; - -funExp(isUndefined, 'b', 'c'); -funExp('a', globalThis.unknown, 'c'); - -const arrow = (a = 'retained', b = 'retained', c = 'removed', d = 'removed') => - console.log(a, b, c); - -arrow(isUndefined, 'b', 'c'); -arrow('a', globalThis.unknown, 'c'); diff --git a/test/form/samples/parameter-defaults/non-literal-arguments/_config.js b/test/form/samples/parameter-defaults/non-literal-arguments/_config.js deleted file mode 100644 index 341af06cb2d..00000000000 --- a/test/form/samples/parameter-defaults/non-literal-arguments/_config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - description: 'recognizes non-literal arguments as not undefined' -}; diff --git a/test/form/samples/parameter-defaults/non-literal-arguments/_expected.js b/test/form/samples/parameter-defaults/non-literal-arguments/_expected.js deleted file mode 100644 index 3ac927db486..00000000000 --- a/test/form/samples/parameter-defaults/non-literal-arguments/_expected.js +++ /dev/null @@ -1,11 +0,0 @@ -function test(a) { - console.log(a); -} - -test({}); -test([]); -test(() => {}); -test(function () {}); -function a(){} -test(a); -test(Symbol); diff --git a/test/form/samples/parameter-defaults/non-literal-arguments/main.js b/test/form/samples/parameter-defaults/non-literal-arguments/main.js deleted file mode 100644 index 6f3421429ae..00000000000 --- a/test/form/samples/parameter-defaults/non-literal-arguments/main.js +++ /dev/null @@ -1,11 +0,0 @@ -function test(a = 'removed') { - console.log(a); -} - -test({}); -test([]); -test(() => {}); -test(function () {}); -function a(){} -test(a); -test(Symbol); diff --git a/test/form/samples/parameter-defaults/side-effects/_config.js b/test/form/samples/parameter-defaults/side-effects/_config.js deleted file mode 100644 index 72e8c1d574e..00000000000 --- a/test/form/samples/parameter-defaults/side-effects/_config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - description: 'side-effects in parameter defaults should not be ignored' -}; diff --git a/test/form/samples/parameter-defaults/side-effects/_expected/amd.js b/test/form/samples/parameter-defaults/side-effects/_expected/amd.js deleted file mode 100644 index 5c6eb650c2d..00000000000 --- a/test/form/samples/parameter-defaults/side-effects/_expected/amd.js +++ /dev/null @@ -1,29 +0,0 @@ -define((function () { 'use strict'; - - const effect = () => console.log( 'effect' ); - - function aDecl ( x = effect() ) {} - aDecl(); - - const aExp = function ( x = effect() ) {}; - aExp(); - - const aArr = ( x = effect() ) => {}; - aArr(); - - function bDecl ( x = effect ) { - x(); - } - bDecl(); - - const bExp = function ( x = effect ) { - x(); - }; - bExp(); - - const bArr = ( x = effect ) => { - x(); - }; - bArr(); - -})); diff --git a/test/form/samples/parameter-defaults/side-effects/_expected/cjs.js b/test/form/samples/parameter-defaults/side-effects/_expected/cjs.js deleted file mode 100644 index db9e8b6e74e..00000000000 --- a/test/form/samples/parameter-defaults/side-effects/_expected/cjs.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; - -const effect = () => console.log( 'effect' ); - -function aDecl ( x = effect() ) {} -aDecl(); - -const aExp = function ( x = effect() ) {}; -aExp(); - -const aArr = ( x = effect() ) => {}; -aArr(); - -function bDecl ( x = effect ) { - x(); -} -bDecl(); - -const bExp = function ( x = effect ) { - x(); -}; -bExp(); - -const bArr = ( x = effect ) => { - x(); -}; -bArr(); diff --git a/test/form/samples/parameter-defaults/side-effects/_expected/es.js b/test/form/samples/parameter-defaults/side-effects/_expected/es.js deleted file mode 100644 index d8c68658ffd..00000000000 --- a/test/form/samples/parameter-defaults/side-effects/_expected/es.js +++ /dev/null @@ -1,25 +0,0 @@ -const effect = () => console.log( 'effect' ); - -function aDecl ( x = effect() ) {} -aDecl(); - -const aExp = function ( x = effect() ) {}; -aExp(); - -const aArr = ( x = effect() ) => {}; -aArr(); - -function bDecl ( x = effect ) { - x(); -} -bDecl(); - -const bExp = function ( x = effect ) { - x(); -}; -bExp(); - -const bArr = ( x = effect ) => { - x(); -}; -bArr(); diff --git a/test/form/samples/parameter-defaults/side-effects/_expected/iife.js b/test/form/samples/parameter-defaults/side-effects/_expected/iife.js deleted file mode 100644 index 2b93c21ad2d..00000000000 --- a/test/form/samples/parameter-defaults/side-effects/_expected/iife.js +++ /dev/null @@ -1,30 +0,0 @@ -(function () { - 'use strict'; - - const effect = () => console.log( 'effect' ); - - function aDecl ( x = effect() ) {} - aDecl(); - - const aExp = function ( x = effect() ) {}; - aExp(); - - const aArr = ( x = effect() ) => {}; - aArr(); - - function bDecl ( x = effect ) { - x(); - } - bDecl(); - - const bExp = function ( x = effect ) { - x(); - }; - bExp(); - - const bArr = ( x = effect ) => { - x(); - }; - bArr(); - -})(); diff --git a/test/form/samples/parameter-defaults/side-effects/_expected/system.js b/test/form/samples/parameter-defaults/side-effects/_expected/system.js deleted file mode 100644 index 8f8694759a3..00000000000 --- a/test/form/samples/parameter-defaults/side-effects/_expected/system.js +++ /dev/null @@ -1,34 +0,0 @@ -System.register([], (function () { - 'use strict'; - return { - execute: (function () { - - const effect = () => console.log( 'effect' ); - - function aDecl ( x = effect() ) {} - aDecl(); - - const aExp = function ( x = effect() ) {}; - aExp(); - - const aArr = ( x = effect() ) => {}; - aArr(); - - function bDecl ( x = effect ) { - x(); - } - bDecl(); - - const bExp = function ( x = effect ) { - x(); - }; - bExp(); - - const bArr = ( x = effect ) => { - x(); - }; - bArr(); - - }) - }; -})); diff --git a/test/form/samples/parameter-defaults/side-effects/_expected/umd.js b/test/form/samples/parameter-defaults/side-effects/_expected/umd.js deleted file mode 100644 index c087fe1e907..00000000000 --- a/test/form/samples/parameter-defaults/side-effects/_expected/umd.js +++ /dev/null @@ -1,32 +0,0 @@ -(function (factory) { - typeof define === 'function' && define.amd ? define(factory) : - factory(); -})((function () { 'use strict'; - - const effect = () => console.log( 'effect' ); - - function aDecl ( x = effect() ) {} - aDecl(); - - const aExp = function ( x = effect() ) {}; - aExp(); - - const aArr = ( x = effect() ) => {}; - aArr(); - - function bDecl ( x = effect ) { - x(); - } - bDecl(); - - const bExp = function ( x = effect ) { - x(); - }; - bExp(); - - const bArr = ( x = effect ) => { - x(); - }; - bArr(); - -})); diff --git a/test/form/samples/parameter-defaults/side-effects/main.js b/test/form/samples/parameter-defaults/side-effects/main.js deleted file mode 100644 index d8c68658ffd..00000000000 --- a/test/form/samples/parameter-defaults/side-effects/main.js +++ /dev/null @@ -1,25 +0,0 @@ -const effect = () => console.log( 'effect' ); - -function aDecl ( x = effect() ) {} -aDecl(); - -const aExp = function ( x = effect() ) {}; -aExp(); - -const aArr = ( x = effect() ) => {}; -aArr(); - -function bDecl ( x = effect ) { - x(); -} -bDecl(); - -const bExp = function ( x = effect ) { - x(); -}; -bExp(); - -const bArr = ( x = effect ) => { - x(); -}; -bArr(); diff --git a/test/form/samples/parameter-defaults/super-class-methods/_config.js b/test/form/samples/parameter-defaults/super-class-methods/_config.js deleted file mode 100644 index 6dbe1e96dd5..00000000000 --- a/test/form/samples/parameter-defaults/super-class-methods/_config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - description: 'supports tree-shaking for unused default parameter values on super classes' -}; diff --git a/test/form/samples/parameter-defaults/super-class-methods/_expected.js b/test/form/samples/parameter-defaults/super-class-methods/_expected.js deleted file mode 100644 index 167fdc9faff..00000000000 --- a/test/form/samples/parameter-defaults/super-class-methods/_expected.js +++ /dev/null @@ -1,17 +0,0 @@ -class TestSuper { - constructor(a = 'retained') { - console.log(a); - } - - static staticMethod(a = 'retained') { - console.log(a); - } - - static staticProp = (a = 'retained') => console.log(a); -} - -class Test extends TestSuper {} - -new Test().method(); -Test.staticMethod(); -Test.staticProp(); diff --git a/test/form/samples/parameter-defaults/super-class-methods/main.js b/test/form/samples/parameter-defaults/super-class-methods/main.js deleted file mode 100644 index 167fdc9faff..00000000000 --- a/test/form/samples/parameter-defaults/super-class-methods/main.js +++ /dev/null @@ -1,17 +0,0 @@ -class TestSuper { - constructor(a = 'retained') { - console.log(a); - } - - static staticMethod(a = 'retained') { - console.log(a); - } - - static staticProp = (a = 'retained') => console.log(a); -} - -class Test extends TestSuper {} - -new Test().method(); -Test.staticMethod(); -Test.staticProp(); diff --git a/test/form/samples/parameter-defaults/termplate-tags/_config.js b/test/form/samples/parameter-defaults/termplate-tags/_config.js deleted file mode 100644 index 6c444966620..00000000000 --- a/test/form/samples/parameter-defaults/termplate-tags/_config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - description: 'supports tree-shaking for unused default parameter values on template tags' -}; diff --git a/test/form/samples/parameter-defaults/termplate-tags/_expected.js b/test/form/samples/parameter-defaults/termplate-tags/_expected.js deleted file mode 100644 index 39bc336e378..00000000000 --- a/test/form/samples/parameter-defaults/termplate-tags/_expected.js +++ /dev/null @@ -1,6 +0,0 @@ -const templateTag = (_, a = 'retained', b = 'retained', c, d) => { - console.log(a, b, c); -}; - -templateTag`${isUndefined}${'b'}${'c'}`; -templateTag`${'a'}${globalThis.unknown}${'c'}`; diff --git a/test/form/samples/parameter-defaults/termplate-tags/main.js b/test/form/samples/parameter-defaults/termplate-tags/main.js deleted file mode 100644 index bed212d6f45..00000000000 --- a/test/form/samples/parameter-defaults/termplate-tags/main.js +++ /dev/null @@ -1,6 +0,0 @@ -const templateTag = (_, a = 'retained', b = 'retained', c = 'removed', d = 'removed') => { - console.log(a, b, c); -}; - -templateTag`${isUndefined}${'b'}${'c'}`; -templateTag`${'a'}${globalThis.unknown}${'c'}`; diff --git a/test/form/samples/treeshake-excess-arguments/unused-parameters/_expected.js b/test/form/samples/treeshake-excess-arguments/unused-parameters/_expected.js index 40313093cf8..256b223b12a 100644 --- a/test/form/samples/treeshake-excess-arguments/unused-parameters/_expected.js +++ b/test/form/samples/treeshake-excess-arguments/unused-parameters/_expected.js @@ -1,9 +1,11 @@ -function test(a, b, c) {} +function test(a, b = globalThis.unknown(), c) {} +test(1, 2); function noEffect() {} test(1, 2, noEffect(), globalThis.unknown()); -const testArr = (a, b, c) => {}; +const testArr = (a, b = globalThis.unknown(), c) => {}; +testArr(1, 2); function noEffectArr() {} testArr(1, 2, noEffectArr(), globalThis.unknown()); diff --git a/test/function/samples/class-method-getter-properties/_config.js b/test/function/samples/class-method-getter-properties/_config.js new file mode 100644 index 00000000000..6a6f5724505 --- /dev/null +++ b/test/function/samples/class-method-getter-properties/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'respects getters added to class methods' +}; diff --git a/test/function/samples/class-method-getter-properties/main.js b/test/function/samples/class-method-getter-properties/main.js new file mode 100644 index 00000000000..eb537bcefb4 --- /dev/null +++ b/test/function/samples/class-method-getter-properties/main.js @@ -0,0 +1,44 @@ +let effect = false; + +class TestSuper { + constructor() { + } + + static bar() {} +} + +class Test extends TestSuper { + constructor() { + super(); + } + + static foo() {} +} + +const setEffect = { + get() { + effect = true; + }, +}; + +const addGetters = obj => { + Object.defineProperty(obj, 'x', setEffect); + Object.defineProperty(obj.foo, 'x', setEffect); + Object.defineProperty(obj.bar, 'x', setEffect); +}; + +const checkEffect = () => { + assert.ok(effect); + effect = false; +}; + +addGetters(Test); + +Test.x; +checkEffect(); + +Test.foo.x; +checkEffect(); + +TestSuper.bar.x; +checkEffect(); diff --git a/test/function/samples/parameter-defaults/return-expressions/_config.js b/test/function/samples/parameter-defaults/return-expressions/_config.js new file mode 100644 index 00000000000..3f3dcca5c3b --- /dev/null +++ b/test/function/samples/parameter-defaults/return-expressions/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'keeps parameter defaults for returned expressions' +}; diff --git a/test/function/samples/parameter-defaults/return-expressions/main.js b/test/function/samples/parameter-defaults/return-expressions/main.js new file mode 100644 index 00000000000..56100f30c07 --- /dev/null +++ b/test/function/samples/parameter-defaults/return-expressions/main.js @@ -0,0 +1,8 @@ +function foo() { + const bar = (options = 'fallback') => { + return options; + }; + return bar; +} + +assert.strictEqual(foo()(), 'fallback'); diff --git a/test/function/samples/parameter-defaults/try-catch/_config.js b/test/function/samples/parameter-defaults/try-catch/_config.js new file mode 100644 index 00000000000..6bc80c6b7e9 --- /dev/null +++ b/test/function/samples/parameter-defaults/try-catch/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'keeps parameter defaults when called from try-statement' +}; diff --git a/test/function/samples/parameter-defaults/try-catch/main.js b/test/function/samples/parameter-defaults/try-catch/main.js new file mode 100644 index 00000000000..f57e731eb4c --- /dev/null +++ b/test/function/samples/parameter-defaults/try-catch/main.js @@ -0,0 +1,9 @@ +const test = (a = 'fallback') => a; + +let returnValue; + +try { + returnValue = test(); +} catch {} + +assert.strictEqual(returnValue, 'fallback');