@rollup/wasm-node 4.32.1 → 4.33.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  @license
3
- Rollup.js v4.32.1
4
- Tue, 28 Jan 2025 08:32:49 GMT - commit abcf4febe11f3d313fae41ddca35fc60670b9ff8
3
+ Rollup.js v4.33.0-0
4
+ Tue, 28 Jan 2025 08:29:38 GMT - commit f854e1988542d09f9691923eddd80888e92240d3
5
5
 
6
6
  https://github.com/rollup/rollup
7
7
 
@@ -17,7 +17,7 @@ const native_js = require('../native.js');
17
17
  const node_perf_hooks = require('node:perf_hooks');
18
18
  const promises = require('node:fs/promises');
19
19
 
20
- var version = "4.32.1";
20
+ var version = "4.33.0-0";
21
21
 
22
22
  function ensureArray$1(items) {
23
23
  if (Array.isArray(items)) {
@@ -3491,71 +3491,6 @@ function renderSystemExportSequenceBeforeExpression(exportedVariable, expression
3491
3491
  }
3492
3492
  }
3493
3493
 
3494
- /** @import { Node } from 'estree' */
3495
-
3496
- /**
3497
- * @param {Node} node
3498
- * @param {Node} parent
3499
- * @returns {boolean}
3500
- */
3501
- function is_reference(node, parent) {
3502
- if (node.type === 'MemberExpression') {
3503
- return !node.computed && is_reference(node.object, node);
3504
- }
3505
-
3506
- if (node.type !== 'Identifier') return false;
3507
-
3508
- switch (parent?.type) {
3509
- // disregard `bar` in `foo.bar`
3510
- case 'MemberExpression':
3511
- return parent.computed || node === parent.object;
3512
-
3513
- // disregard the `foo` in `class {foo(){}}` but keep it in `class {[foo](){}}`
3514
- case 'MethodDefinition':
3515
- return parent.computed;
3516
-
3517
- // disregard the `meta` in `import.meta`
3518
- case 'MetaProperty':
3519
- return parent.meta === node;
3520
-
3521
- // disregard the `foo` in `class {foo=bar}` but keep it in `class {[foo]=bar}` and `class {bar=foo}`
3522
- case 'PropertyDefinition':
3523
- return parent.computed || node === parent.value;
3524
-
3525
- // disregard the `bar` in `{ bar: foo }`, but keep it in `{ [bar]: foo }`
3526
- case 'Property':
3527
- return parent.computed || node === parent.value;
3528
-
3529
- // disregard the `bar` in `export { foo as bar }` or
3530
- // the foo in `import { foo as bar }`
3531
- case 'ExportSpecifier':
3532
- case 'ImportSpecifier':
3533
- return node === parent.local;
3534
-
3535
- // disregard the `foo` in `foo: while (...) { ... break foo; ... continue foo;}`
3536
- case 'LabeledStatement':
3537
- case 'BreakStatement':
3538
- case 'ContinueStatement':
3539
- return false;
3540
-
3541
- default:
3542
- return true;
3543
- }
3544
- }
3545
-
3546
- const PureFunctionKey = Symbol('PureFunction');
3547
- const getPureFunctions = ({ treeshake }) => {
3548
- const pureFunctions = Object.create(null);
3549
- for (const functionName of treeshake ? treeshake.manualPureFunctions : []) {
3550
- let currentFunctions = pureFunctions;
3551
- for (const pathSegment of functionName.split('.')) {
3552
- currentFunctions = currentFunctions[pathSegment] ||= Object.create(null);
3553
- }
3554
- currentFunctions[PureFunctionKey] = true;
3555
- }
3556
- return pureFunctions;
3557
- };
3558
-
3559
3494
  const UnknownKey = Symbol('Unknown Key');
3560
3495
  const UnknownNonAccessorKey = Symbol('Unknown Non-Accessor Key');
3561
3496
  const UnknownInteger = Symbol('Unknown Integer');
@@ -3570,7 +3505,7 @@ const UNKNOWN_PATH = [UnknownKey];
3570
3505
  const UNKNOWN_NON_ACCESSOR_PATH = [UnknownNonAccessorKey];
3571
3506
  const UNKNOWN_INTEGER_PATH = [UnknownInteger];
3572
3507
  const EntitiesKey = Symbol('Entities');
3573
- class PathTracker {
3508
+ class EntityPathTracker {
3574
3509
  constructor() {
3575
3510
  this.entityPaths = Object.create(null, {
3576
3511
  [EntitiesKey]: { value: new Set() }
@@ -3595,14 +3530,14 @@ class PathTracker {
3595
3530
  getEntities(path) {
3596
3531
  let currentPaths = this.entityPaths;
3597
3532
  for (const pathSegment of path) {
3598
- currentPaths = currentPaths[pathSegment] =
3599
- currentPaths[pathSegment] ||
3600
- Object.create(null, { [EntitiesKey]: { value: new Set() } });
3533
+ currentPaths = currentPaths[pathSegment] ||= Object.create(null, {
3534
+ [EntitiesKey]: { value: new Set() }
3535
+ });
3601
3536
  }
3602
3537
  return currentPaths[EntitiesKey];
3603
3538
  }
3604
3539
  }
3605
- const SHARED_RECURSION_TRACKER = new PathTracker();
3540
+ const SHARED_RECURSION_TRACKER = new EntityPathTracker();
3606
3541
  class DiscriminatedPathTracker {
3607
3542
  constructor() {
3608
3543
  this.entityPaths = Object.create(null, {
@@ -3612,9 +3547,9 @@ class DiscriminatedPathTracker {
3612
3547
  trackEntityAtPathAndGetIfTracked(path, discriminator, entity) {
3613
3548
  let currentPaths = this.entityPaths;
3614
3549
  for (const pathSegment of path) {
3615
- currentPaths = currentPaths[pathSegment] =
3616
- currentPaths[pathSegment] ||
3617
- Object.create(null, { [EntitiesKey]: { value: new Map() } });
3550
+ currentPaths = currentPaths[pathSegment] ||= Object.create(null, {
3551
+ [EntitiesKey]: { value: new Map() }
3552
+ });
3618
3553
  }
3619
3554
  const trackedEntities = getOrCreate(currentPaths[EntitiesKey], discriminator, (getNewSet));
3620
3555
  if (trackedEntities.has(entity))
@@ -3623,6 +3558,174 @@ class DiscriminatedPathTracker {
3623
3558
  return false;
3624
3559
  }
3625
3560
  }
3561
+ const UNKNOWN_INCLUDED_PATH = Object.freeze({ [UnknownKey]: parseAst_js.EMPTY_OBJECT });
3562
+ class IncludedFullPathTracker {
3563
+ constructor() {
3564
+ this.includedPaths = null;
3565
+ }
3566
+ includePathAndGetIfIncluded(path) {
3567
+ let included = true;
3568
+ let parent = this;
3569
+ let parentSegment = 'includedPaths';
3570
+ let currentPaths = (this.includedPaths ||=
3571
+ ((included = false), Object.create(null)));
3572
+ for (const pathSegment of path) {
3573
+ // This means from here, all paths are included
3574
+ if (currentPaths[UnknownKey]) {
3575
+ return true;
3576
+ }
3577
+ // Including UnknownKey automatically includes all nested paths.
3578
+ // From above, we know that UnknownKey is not included yet.
3579
+ if (typeof pathSegment === 'symbol') {
3580
+ // Hopefully, this saves some memory over just setting
3581
+ // currentPaths[UnknownKey] = EMPTY_OBJECT
3582
+ parent[parentSegment] = UNKNOWN_INCLUDED_PATH;
3583
+ return false;
3584
+ }
3585
+ parent = currentPaths;
3586
+ parentSegment = pathSegment;
3587
+ currentPaths = currentPaths[pathSegment] ||= ((included = false), Object.create(null));
3588
+ }
3589
+ return included;
3590
+ }
3591
+ }
3592
+ const UNKNOWN_INCLUDED_TOP_LEVEL_PATH = Object.freeze({
3593
+ [UnknownKey]: true
3594
+ });
3595
+ class IncludedTopLevelPathTracker {
3596
+ constructor() {
3597
+ this.includedPaths = null;
3598
+ }
3599
+ includePathAndGetIfIncluded(path) {
3600
+ let included = true;
3601
+ const includedPaths = (this.includedPaths ||=
3602
+ ((included = false), Object.create(null)));
3603
+ if (includedPaths[UnknownKey]) {
3604
+ return true;
3605
+ }
3606
+ const [firstPathSegment, secondPathSegment] = path;
3607
+ if (!firstPathSegment) {
3608
+ return included;
3609
+ }
3610
+ if (typeof firstPathSegment === 'symbol') {
3611
+ this.includedPaths = UNKNOWN_INCLUDED_TOP_LEVEL_PATH;
3612
+ return false;
3613
+ }
3614
+ if (secondPathSegment) {
3615
+ if (includedPaths[firstPathSegment] === UnknownKey) {
3616
+ return true;
3617
+ }
3618
+ includedPaths[firstPathSegment] = UnknownKey;
3619
+ return false;
3620
+ }
3621
+ if (includedPaths[firstPathSegment]) {
3622
+ return true;
3623
+ }
3624
+ includedPaths[firstPathSegment] = true;
3625
+ return false;
3626
+ }
3627
+ includeAllPaths(entity, context, basePath) {
3628
+ const { includedPaths } = this;
3629
+ if (includedPaths) {
3630
+ if (includedPaths[UnknownKey]) {
3631
+ entity.includePath([...basePath, UnknownKey], context);
3632
+ }
3633
+ else {
3634
+ const inclusionEntries = Object.entries(includedPaths);
3635
+ if (inclusionEntries.length === 0) {
3636
+ entity.includePath(basePath, context);
3637
+ }
3638
+ else {
3639
+ for (const [key, value] of inclusionEntries) {
3640
+ entity.includePath(value === UnknownKey ? [...basePath, key, UnknownKey] : [...basePath, key], context);
3641
+ }
3642
+ }
3643
+ }
3644
+ }
3645
+ }
3646
+ }
3647
+
3648
+ /** @import { Node } from 'estree' */
3649
+
3650
+ /**
3651
+ * @param {Node} node
3652
+ * @param {Node} parent
3653
+ * @returns {boolean}
3654
+ */
3655
+ function is_reference(node, parent) {
3656
+ if (node.type === 'MemberExpression') {
3657
+ return !node.computed && is_reference(node.object, node);
3658
+ }
3659
+
3660
+ if (node.type !== 'Identifier') return false;
3661
+
3662
+ switch (parent?.type) {
3663
+ // disregard `bar` in `foo.bar`
3664
+ case 'MemberExpression':
3665
+ return parent.computed || node === parent.object;
3666
+
3667
+ // disregard the `foo` in `class {foo(){}}` but keep it in `class {[foo](){}}`
3668
+ case 'MethodDefinition':
3669
+ return parent.computed;
3670
+
3671
+ // disregard the `meta` in `import.meta`
3672
+ case 'MetaProperty':
3673
+ return parent.meta === node;
3674
+
3675
+ // disregard the `foo` in `class {foo=bar}` but keep it in `class {[foo]=bar}` and `class {bar=foo}`
3676
+ case 'PropertyDefinition':
3677
+ return parent.computed || node === parent.value;
3678
+
3679
+ // disregard the `bar` in `{ bar: foo }`, but keep it in `{ [bar]: foo }`
3680
+ case 'Property':
3681
+ return parent.computed || node === parent.value;
3682
+
3683
+ // disregard the `bar` in `export { foo as bar }` or
3684
+ // the foo in `import { foo as bar }`
3685
+ case 'ExportSpecifier':
3686
+ case 'ImportSpecifier':
3687
+ return node === parent.local;
3688
+
3689
+ // disregard the `foo` in `foo: while (...) { ... break foo; ... continue foo;}`
3690
+ case 'LabeledStatement':
3691
+ case 'BreakStatement':
3692
+ case 'ContinueStatement':
3693
+ return false;
3694
+
3695
+ default:
3696
+ return true;
3697
+ }
3698
+ }
3699
+
3700
+ function createInclusionContext() {
3701
+ return {
3702
+ brokenFlow: false,
3703
+ hasBreak: false,
3704
+ hasContinue: false,
3705
+ includedCallArguments: new Set(),
3706
+ includedLabels: new Set()
3707
+ };
3708
+ }
3709
+ function createHasEffectsContext() {
3710
+ return {
3711
+ accessed: new EntityPathTracker(),
3712
+ assigned: new EntityPathTracker(),
3713
+ brokenFlow: false,
3714
+ called: new DiscriminatedPathTracker(),
3715
+ hasBreak: false,
3716
+ hasContinue: false,
3717
+ ignore: {
3718
+ breaks: false,
3719
+ continues: false,
3720
+ labels: new Set(),
3721
+ returnYield: false,
3722
+ this: false
3723
+ },
3724
+ includedLabels: new Set(),
3725
+ instantiated: new DiscriminatedPathTracker(),
3726
+ replacedVariableInits: new Map()
3727
+ };
3728
+ }
3626
3729
 
3627
3730
  function isFlagSet(flags, flag) {
3628
3731
  return (flags & flag) !== 0;
@@ -3662,12 +3765,25 @@ class ExpressionEntity {
3662
3765
  hasEffectsOnInteractionAtPath(_path, _interaction, _context) {
3663
3766
  return true;
3664
3767
  }
3665
- include(_context, _includeChildrenRecursively, _options) {
3768
+ include(context, _includeChildrenRecursively, _options) {
3769
+ if (!this.included)
3770
+ this.includeNode(context);
3771
+ }
3772
+ includeNode(_context) {
3666
3773
  this.included = true;
3667
3774
  }
3668
- includeCallArguments(context, parameters) {
3669
- for (const argument of parameters) {
3670
- argument.include(context, false);
3775
+ includePath(_path, context) {
3776
+ if (!this.included)
3777
+ this.includeNode(context);
3778
+ }
3779
+ /* We are both including and including an unknown path here as the former
3780
+ * ensures that nested nodes are included while the latter ensures that all
3781
+ * paths of the expression are included.
3782
+ * */
3783
+ includeCallArguments(context, interaction) {
3784
+ for (const argument of interaction.args) {
3785
+ argument?.includePath(UNKNOWN_PATH, context);
3786
+ argument?.include(context, false);
3671
3787
  }
3672
3788
  }
3673
3789
  shouldBeIncluded(_context) {
@@ -3706,6 +3822,19 @@ const NODE_INTERACTION_UNKNOWN_CALL = {
3706
3822
  withNew: false
3707
3823
  };
3708
3824
 
3825
+ const PureFunctionKey = Symbol('PureFunction');
3826
+ const getPureFunctions = ({ treeshake }) => {
3827
+ const pureFunctions = Object.create(null);
3828
+ for (const functionName of treeshake ? treeshake.manualPureFunctions : []) {
3829
+ let currentFunctions = pureFunctions;
3830
+ for (const pathSegment of functionName.split('.')) {
3831
+ currentFunctions = currentFunctions[pathSegment] ||= Object.create(null);
3832
+ }
3833
+ currentFunctions[PureFunctionKey] = true;
3834
+ }
3835
+ return pureFunctions;
3836
+ };
3837
+
3709
3838
  class Variable extends ExpressionEntity {
3710
3839
  markReassigned() {
3711
3840
  this.isReassigned = true;
@@ -3782,9 +3911,9 @@ class Variable extends ExpressionEntity {
3782
3911
  * has not been included previously. Once a variable is included, it should
3783
3912
  * take care all its declarations are included.
3784
3913
  */
3785
- include() {
3914
+ includePath(path, context) {
3786
3915
  this.included = true;
3787
- this.renderedLikeHoisted?.include();
3916
+ this.renderedLikeHoisted?.includePath(path, context);
3788
3917
  }
3789
3918
  /**
3790
3919
  * Links the rendered name of this variable to another variable and includes
@@ -3816,8 +3945,8 @@ class ExternalVariable extends Variable {
3816
3945
  hasEffectsOnInteractionAtPath(path, { type }) {
3817
3946
  return type !== INTERACTION_ACCESSED || path.length > (this.isNamespace ? 1 : 0);
3818
3947
  }
3819
- include() {
3820
- super.include();
3948
+ includePath(path, context) {
3949
+ super.includePath(path, context);
3821
3950
  this.module.used = true;
3822
3951
  }
3823
3952
  }
@@ -4116,36 +4245,6 @@ const childNodeKeys = {
4116
4245
  YieldExpression: ['argument']
4117
4246
  };
4118
4247
 
4119
- function createInclusionContext() {
4120
- return {
4121
- brokenFlow: false,
4122
- hasBreak: false,
4123
- hasContinue: false,
4124
- includedCallArguments: new Set(),
4125
- includedLabels: new Set()
4126
- };
4127
- }
4128
- function createHasEffectsContext() {
4129
- return {
4130
- accessed: new PathTracker(),
4131
- assigned: new PathTracker(),
4132
- brokenFlow: false,
4133
- called: new DiscriminatedPathTracker(),
4134
- hasBreak: false,
4135
- hasContinue: false,
4136
- ignore: {
4137
- breaks: false,
4138
- continues: false,
4139
- labels: new Set(),
4140
- returnYield: false,
4141
- this: false
4142
- },
4143
- includedLabels: new Set(),
4144
- instantiated: new DiscriminatedPathTracker(),
4145
- replacedVariableInits: new Map()
4146
- };
4147
- }
4148
-
4149
4248
  const INCLUDE_PARAMETERS = 'variables';
4150
4249
  const IS_SKIPPED_CHAIN = Symbol('IS_SKIPPED_CHAIN');
4151
4250
  class NodeBase extends ExpressionEntity {
@@ -4215,9 +4314,8 @@ class NodeBase extends ExpressionEntity {
4215
4314
  this.hasEffectsOnInteractionAtPath(EMPTY_PATH, this.assignmentInteraction, context));
4216
4315
  }
4217
4316
  include(context, includeChildrenRecursively, _options) {
4218
- if (!this.deoptimized)
4219
- this.applyDeoptimizations();
4220
- this.included = true;
4317
+ if (!this.included)
4318
+ this.includeNode(context);
4221
4319
  for (const key of childNodeKeys[this.type]) {
4222
4320
  const value = this[key];
4223
4321
  if (value === null)
@@ -4232,6 +4330,24 @@ class NodeBase extends ExpressionEntity {
4232
4330
  }
4233
4331
  }
4234
4332
  }
4333
+ includeNode(context) {
4334
+ this.included = true;
4335
+ if (!this.deoptimized)
4336
+ this.applyDeoptimizations();
4337
+ for (const key of childNodeKeys[this.type]) {
4338
+ const value = this[key];
4339
+ if (value === null)
4340
+ continue;
4341
+ if (Array.isArray(value)) {
4342
+ for (const child of value) {
4343
+ child?.includePath(UNKNOWN_PATH, context);
4344
+ }
4345
+ }
4346
+ else {
4347
+ value.includePath(UNKNOWN_PATH, context);
4348
+ }
4349
+ }
4350
+ }
4235
4351
  includeAsAssignmentTarget(context, includeChildrenRecursively, _deoptimizeAccess) {
4236
4352
  this.include(context, includeChildrenRecursively);
4237
4353
  }
@@ -4335,6 +4451,17 @@ class NodeBase extends ExpressionEntity {
4335
4451
  function createChildNodeKeysForNode(esTreeNode) {
4336
4452
  return Object.keys(esTreeNode).filter(key => typeof esTreeNode[key] === 'object' && key.charCodeAt(0) !== 95 /* _ */);
4337
4453
  }
4454
+ function onlyIncludeSelf() {
4455
+ this.included = true;
4456
+ if (!this.deoptimized)
4457
+ this.applyDeoptimizations();
4458
+ }
4459
+ function onlyIncludeSelfNoDeoptimize() {
4460
+ this.included = true;
4461
+ }
4462
+ function doNotDeoptimize() {
4463
+ this.deoptimized = true;
4464
+ }
4338
4465
 
4339
4466
  function isObjectExpressionNode(node) {
4340
4467
  return node instanceof NodeBase && node.type === parseAst_js.ObjectExpression;
@@ -4347,8 +4474,8 @@ function assembleMemberDescriptions(memberDescriptions, inheritedDescriptions =
4347
4474
  return Object.create(inheritedDescriptions, memberDescriptions);
4348
4475
  }
4349
4476
  const UNDEFINED_EXPRESSION = new (class UndefinedExpression extends ExpressionEntity {
4350
- getLiteralValueAtPath() {
4351
- return undefined;
4477
+ getLiteralValueAtPath(path) {
4478
+ return path.length > 0 ? UnknownValue : undefined;
4352
4479
  }
4353
4480
  })();
4354
4481
  const returnsUnknown = {
@@ -4545,31 +4672,6 @@ function getMemberReturnExpressionWhenCalled(members, memberName) {
4545
4672
  return [members[memberName].returns, false];
4546
4673
  }
4547
4674
 
4548
- class SpreadElement extends NodeBase {
4549
- deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
4550
- if (path.length > 0) {
4551
- this.argument.deoptimizeArgumentsOnInteractionAtPath(interaction, UNKNOWN_PATH, recursionTracker);
4552
- }
4553
- }
4554
- hasEffects(context) {
4555
- if (!this.deoptimized)
4556
- this.applyDeoptimizations();
4557
- const { propertyReadSideEffects } = this.scope.context.options
4558
- .treeshake;
4559
- return (this.argument.hasEffects(context) ||
4560
- (propertyReadSideEffects &&
4561
- (propertyReadSideEffects === 'always' ||
4562
- this.argument.hasEffectsOnInteractionAtPath(UNKNOWN_PATH, NODE_INTERACTION_UNKNOWN_ACCESS, context))));
4563
- }
4564
- applyDeoptimizations() {
4565
- this.deoptimized = true;
4566
- // Only properties of properties of the argument could become subject to reassignment
4567
- // This will also reassign the return values of iterators
4568
- this.argument.deoptimizePath([UnknownKey, UnknownKey]);
4569
- this.scope.context.requestTreeshakingPass();
4570
- }
4571
- }
4572
-
4573
4675
  class Method extends ExpressionEntity {
4574
4676
  constructor(description) {
4575
4677
  super();
@@ -4695,6 +4797,7 @@ class ObjectEntity extends ExpressionEntity {
4695
4797
  this.unknownIntegerProps = [];
4696
4798
  this.unmatchableGetters = [];
4697
4799
  this.unmatchablePropertiesAndGetters = [];
4800
+ this.unmatchablePropertiesAndSetters = [];
4698
4801
  this.unmatchableSetters = [];
4699
4802
  if (Array.isArray(properties)) {
4700
4803
  this.buildPropertyMaps(properties);
@@ -4851,7 +4954,12 @@ class ObjectEntity extends ExpressionEntity {
4851
4954
  }
4852
4955
  getLiteralValueAtPath(path, recursionTracker, origin) {
4853
4956
  if (path.length === 0) {
4854
- return UnknownTruthyValue;
4957
+ // This should actually be "UnknownTruthyValue". However, this currently
4958
+ // causes an issue with TypeScript enums in files with moduleSideEffects:
4959
+ // false because we cannot properly track whether a "var" has been
4960
+ // initialized. This should be reverted once we can properly track this.
4961
+ // return UnknownTruthyValue;
4962
+ return UnknownValue;
4855
4963
  }
4856
4964
  const key = path[0];
4857
4965
  const expressionAtPath = this.getMemberExpressionAndTrackDeopt(key, origin);
@@ -4929,9 +5037,36 @@ class ObjectEntity extends ExpressionEntity {
4929
5037
  }
4930
5038
  return false;
4931
5039
  }
5040
+ include(context, includeChildrenRecursively) {
5041
+ this.included = true;
5042
+ for (const property of this.allProperties) {
5043
+ if (includeChildrenRecursively || property.shouldBeIncluded(context)) {
5044
+ property.include(context, includeChildrenRecursively);
5045
+ }
5046
+ }
5047
+ this.prototypeExpression?.include(context, includeChildrenRecursively);
5048
+ }
5049
+ includePath(path, context) {
5050
+ this.included = true;
5051
+ if (path.length === 0)
5052
+ return;
5053
+ const [key, ...subPath] = path;
5054
+ const [includedMembers, includedPath] = typeof key === 'string'
5055
+ ? [
5056
+ new Set([
5057
+ ...(this.propertiesAndGettersByKey[key] || this.unmatchablePropertiesAndGetters),
5058
+ ...(this.propertiesAndSettersByKey[key] || this.unmatchablePropertiesAndSetters)
5059
+ ]),
5060
+ subPath
5061
+ ]
5062
+ : [this.allProperties, UNKNOWN_PATH];
5063
+ for (const property of includedMembers) {
5064
+ property.includePath(includedPath, context);
5065
+ }
5066
+ this.prototypeExpression?.includePath(path, context);
5067
+ }
4932
5068
  buildPropertyMaps(properties) {
4933
- const { allProperties, propertiesAndGettersByKey, propertiesAndSettersByKey, settersByKey, gettersByKey, unknownIntegerProps, unmatchablePropertiesAndGetters, unmatchableGetters, unmatchableSetters } = this;
4934
- const unmatchablePropertiesAndSetters = [];
5069
+ const { allProperties, propertiesAndGettersByKey, propertiesAndSettersByKey, settersByKey, gettersByKey, unknownIntegerProps, unmatchablePropertiesAndGetters, unmatchablePropertiesAndSetters, unmatchableGetters, unmatchableSetters } = this;
4935
5070
  for (let index = properties.length - 1; index >= 0; index--) {
4936
5071
  const { key, kind, property } = properties[index];
4937
5072
  allProperties.push(property);
@@ -5201,6 +5336,37 @@ const ARRAY_PROTOTYPE = new ObjectEntity({
5201
5336
  values: METHOD_DEOPTS_SELF_RETURNS_UNKNOWN
5202
5337
  }, OBJECT_PROTOTYPE, true);
5203
5338
 
5339
+ class SpreadElement extends NodeBase {
5340
+ deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
5341
+ if (path.length > 0) {
5342
+ this.argument.deoptimizeArgumentsOnInteractionAtPath(interaction, UNKNOWN_PATH, recursionTracker);
5343
+ }
5344
+ }
5345
+ hasEffects(context) {
5346
+ if (!this.deoptimized)
5347
+ this.applyDeoptimizations();
5348
+ const { propertyReadSideEffects } = this.scope.context.options
5349
+ .treeshake;
5350
+ return (this.argument.hasEffects(context) ||
5351
+ (propertyReadSideEffects &&
5352
+ (propertyReadSideEffects === 'always' ||
5353
+ this.argument.hasEffectsOnInteractionAtPath(UNKNOWN_PATH, NODE_INTERACTION_UNKNOWN_ACCESS, context))));
5354
+ }
5355
+ includeNode(context) {
5356
+ this.included = true;
5357
+ if (!this.deoptimized)
5358
+ this.applyDeoptimizations();
5359
+ this.argument.includePath(UNKNOWN_PATH, context);
5360
+ }
5361
+ applyDeoptimizations() {
5362
+ this.deoptimized = true;
5363
+ // Only properties of properties of the argument could become subject to reassignment
5364
+ // This will also reassign the return values of iterators
5365
+ this.argument.deoptimizePath([UnknownKey, UnknownKey]);
5366
+ this.scope.context.requestTreeshakingPass();
5367
+ }
5368
+ }
5369
+
5204
5370
  class ArrayExpression extends NodeBase {
5205
5371
  constructor() {
5206
5372
  super(...arguments);
@@ -5221,6 +5387,16 @@ class ArrayExpression extends NodeBase {
5221
5387
  hasEffectsOnInteractionAtPath(path, interaction, context) {
5222
5388
  return this.getObjectEntity().hasEffectsOnInteractionAtPath(path, interaction, context);
5223
5389
  }
5390
+ includeNode(context) {
5391
+ this.included = true;
5392
+ if (!this.deoptimized)
5393
+ this.applyDeoptimizations();
5394
+ for (const element of this.elements) {
5395
+ if (element) {
5396
+ element?.includePath(UNKNOWN_PATH, context);
5397
+ }
5398
+ }
5399
+ }
5224
5400
  applyDeoptimizations() {
5225
5401
  this.deoptimized = true;
5226
5402
  let hasSpread = false;
@@ -6288,17 +6464,37 @@ class GlobalVariable extends Variable {
6288
6464
  }
6289
6465
  }
6290
6466
 
6467
+ // To avoid infinite recursions
6468
+ const MAX_PATH_DEPTH = 6;
6469
+ // If a path is longer than MAX_PATH_DEPTH, it is truncated so that it is at
6470
+ // most MAX_PATH_DEPTH long. The last element is always UnknownKey
6471
+ const limitConcatenatedPathDepth = (path1, path2) => {
6472
+ const { length: length1 } = path1;
6473
+ const { length: length2 } = path2;
6474
+ return length1 === 0
6475
+ ? path2
6476
+ : length2 === 0
6477
+ ? path1
6478
+ : length1 + length2 > MAX_PATH_DEPTH
6479
+ ? [...path1, ...path2.slice(0, MAX_PATH_DEPTH - 1 - path1.length), 'UnknownKey']
6480
+ : [...path1, ...path2];
6481
+ };
6482
+
6291
6483
  class LocalVariable extends Variable {
6292
- constructor(name, declarator, init, context, kind) {
6484
+ constructor(name, declarator, init,
6485
+ /** if this is non-empty, the actual init is this path of this.init */
6486
+ initPath, context, kind) {
6293
6487
  super(name);
6294
6488
  this.init = init;
6489
+ this.initPath = initPath;
6490
+ this.kind = kind;
6295
6491
  this.calledFromTryStatement = false;
6296
6492
  this.additionalInitializers = null;
6493
+ this.includedPathTracker = new IncludedFullPathTracker();
6297
6494
  this.expressionsToBeDeoptimized = [];
6298
6495
  this.declarations = declarator ? [declarator] : [];
6299
6496
  this.deoptimizationTracker = context.deoptimizationTracker;
6300
6497
  this.module = context.module;
6301
- this.kind = kind;
6302
6498
  }
6303
6499
  addDeclaration(identifier, init) {
6304
6500
  this.declarations.push(identifier);
@@ -6309,15 +6505,16 @@ class LocalVariable extends Variable {
6309
6505
  for (const initializer of this.additionalInitializers) {
6310
6506
  initializer.deoptimizePath(UNKNOWN_PATH);
6311
6507
  }
6312
- this.additionalInitializers = null;
6313
6508
  }
6314
6509
  }
6315
6510
  deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
6316
- if (this.isReassigned) {
6511
+ if (this.isReassigned || path.length + this.initPath.length > MAX_PATH_DEPTH) {
6317
6512
  deoptimizeInteraction(interaction);
6318
6513
  return;
6319
6514
  }
6320
- recursionTracker.withTrackedEntityAtPath(path, this.init, () => this.init.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker), undefined);
6515
+ recursionTracker.withTrackedEntityAtPath(path, this.init, () => {
6516
+ this.init.deoptimizeArgumentsOnInteractionAtPath(interaction, [...this.initPath, ...path], recursionTracker);
6517
+ }, undefined);
6321
6518
  }
6322
6519
  deoptimizePath(path) {
6323
6520
  if (this.isReassigned ||
@@ -6331,37 +6528,40 @@ class LocalVariable extends Variable {
6331
6528
  for (const expression of expressionsToBeDeoptimized) {
6332
6529
  expression.deoptimizeCache();
6333
6530
  }
6334
- this.init.deoptimizePath(UNKNOWN_PATH);
6531
+ this.init.deoptimizePath([...this.initPath, UnknownKey]);
6335
6532
  }
6336
6533
  else {
6337
- this.init.deoptimizePath(path);
6534
+ this.init.deoptimizePath(limitConcatenatedPathDepth(this.initPath, path));
6338
6535
  }
6339
6536
  }
6340
6537
  getLiteralValueAtPath(path, recursionTracker, origin) {
6341
- if (this.isReassigned) {
6538
+ if (this.isReassigned || path.length + this.initPath.length > MAX_PATH_DEPTH) {
6342
6539
  return UnknownValue;
6343
6540
  }
6344
6541
  return recursionTracker.withTrackedEntityAtPath(path, this.init, () => {
6345
6542
  this.expressionsToBeDeoptimized.push(origin);
6346
- return this.init.getLiteralValueAtPath(path, recursionTracker, origin);
6543
+ return this.init.getLiteralValueAtPath([...this.initPath, ...path], recursionTracker, origin);
6347
6544
  }, UnknownValue);
6348
6545
  }
6349
6546
  getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
6350
- if (this.isReassigned) {
6547
+ if (this.isReassigned || path.length + this.initPath.length > MAX_PATH_DEPTH) {
6351
6548
  return UNKNOWN_RETURN_EXPRESSION;
6352
6549
  }
6353
6550
  return recursionTracker.withTrackedEntityAtPath(path, this.init, () => {
6354
6551
  this.expressionsToBeDeoptimized.push(origin);
6355
- return this.init.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
6552
+ return this.init.getReturnExpressionWhenCalledAtPath([...this.initPath, ...path], interaction, recursionTracker, origin);
6356
6553
  }, UNKNOWN_RETURN_EXPRESSION);
6357
6554
  }
6358
6555
  hasEffectsOnInteractionAtPath(path, interaction, context) {
6556
+ if (path.length + this.initPath.length > MAX_PATH_DEPTH) {
6557
+ return true;
6558
+ }
6359
6559
  switch (interaction.type) {
6360
6560
  case INTERACTION_ACCESSED: {
6361
6561
  if (this.isReassigned)
6362
6562
  return true;
6363
6563
  return (!context.accessed.trackEntityAtPathAndGetIfTracked(path, this) &&
6364
- this.init.hasEffectsOnInteractionAtPath(path, interaction, context));
6564
+ this.init.hasEffectsOnInteractionAtPath([...this.initPath, ...path], interaction, context));
6365
6565
  }
6366
6566
  case INTERACTION_ASSIGNED: {
6367
6567
  if (this.included)
@@ -6371,44 +6571,63 @@ class LocalVariable extends Variable {
6371
6571
  if (this.isReassigned)
6372
6572
  return true;
6373
6573
  return (!context.assigned.trackEntityAtPathAndGetIfTracked(path, this) &&
6374
- this.init.hasEffectsOnInteractionAtPath(path, interaction, context));
6574
+ this.init.hasEffectsOnInteractionAtPath([...this.initPath, ...path], interaction, context));
6375
6575
  }
6376
6576
  case INTERACTION_CALLED: {
6377
6577
  if (this.isReassigned)
6378
6578
  return true;
6379
6579
  return (!(interaction.withNew ? context.instantiated : context.called).trackEntityAtPathAndGetIfTracked(path, interaction.args, this) &&
6380
- this.init.hasEffectsOnInteractionAtPath(path, interaction, context));
6580
+ this.init.hasEffectsOnInteractionAtPath([...this.initPath, ...path], interaction, context));
6381
6581
  }
6382
6582
  }
6383
6583
  }
6384
- include() {
6385
- if (!this.included) {
6386
- super.include();
6584
+ includePath(path, context) {
6585
+ if (!this.includedPathTracker.includePathAndGetIfIncluded(path)) {
6586
+ this.module.scope.context.requestTreeshakingPass();
6587
+ if (!this.included) {
6588
+ // This will reduce the number of tree-shaking passes by eagerly
6589
+ // including inits. By pushing this here instead of directly including
6590
+ // we avoid deep call stacks.
6591
+ this.module.scope.context.newlyIncludedVariableInits.add(this.init);
6592
+ }
6593
+ super.includePath(path, context);
6387
6594
  for (const declaration of this.declarations) {
6388
6595
  // If node is a default export, it can save a tree-shaking run to include the full declaration now
6389
6596
  if (!declaration.included)
6390
- declaration.include(createInclusionContext(), false);
6597
+ declaration.include(context, false);
6391
6598
  let node = declaration.parent;
6392
6599
  while (!node.included) {
6393
6600
  // We do not want to properly include parents in case they are part of a dead branch
6394
6601
  // in which case .include() might pull in more dead code
6395
- node.included = true;
6602
+ node.includeNode(context);
6396
6603
  if (node.type === parseAst_js.Program)
6397
6604
  break;
6398
6605
  node = node.parent;
6399
6606
  }
6400
6607
  }
6608
+ // We need to make sure we include the correct path of the init
6609
+ if (path.length > 0) {
6610
+ this.init.includePath(limitConcatenatedPathDepth(this.initPath, path), context);
6611
+ this.additionalInitializers?.forEach(initializer => initializer.includePath(UNKNOWN_PATH, context));
6612
+ }
6401
6613
  }
6402
6614
  }
6403
- includeCallArguments(context, parameters) {
6404
- if (this.isReassigned || context.includedCallArguments.has(this.init)) {
6405
- for (const argument of parameters) {
6406
- argument.include(context, false);
6615
+ includeCallArguments(context, interaction) {
6616
+ if (this.isReassigned ||
6617
+ context.includedCallArguments.has(this.init) ||
6618
+ // This can be removed again once we can include arguments when called at
6619
+ // a specific path
6620
+ this.initPath.length > 0) {
6621
+ for (const argument of interaction.args) {
6622
+ if (argument) {
6623
+ argument.includePath(UNKNOWN_PATH, context);
6624
+ argument.include(context, false);
6625
+ }
6407
6626
  }
6408
6627
  }
6409
6628
  else {
6410
6629
  context.includedCallArguments.add(this.init);
6411
- this.init.includeCallArguments(context, parameters);
6630
+ this.init.includeCallArguments(context, interaction);
6412
6631
  context.includedCallArguments.delete(this.init);
6413
6632
  }
6414
6633
  }
@@ -6488,18 +6707,31 @@ class IdentifierBase extends NodeBase {
6488
6707
  }
6489
6708
  }
6490
6709
  }
6491
- include() {
6710
+ include(context) {
6711
+ if (!this.included)
6712
+ this.includeNode(context);
6713
+ }
6714
+ includeNode(context) {
6715
+ this.included = true;
6492
6716
  if (!this.deoptimized)
6493
6717
  this.applyDeoptimizations();
6718
+ if (this.variable !== null) {
6719
+ this.scope.context.includeVariableInModule(this.variable, EMPTY_PATH, context);
6720
+ }
6721
+ }
6722
+ includePath(path, context) {
6494
6723
  if (!this.included) {
6495
6724
  this.included = true;
6496
6725
  if (this.variable !== null) {
6497
- this.scope.context.includeVariableInModule(this.variable);
6726
+ this.scope.context.includeVariableInModule(this.variable, path, context);
6498
6727
  }
6499
6728
  }
6729
+ else if (path.length > 0) {
6730
+ this.variable?.includePath(path, context);
6731
+ }
6500
6732
  }
6501
- includeCallArguments(context, parameters) {
6502
- this.variable.includeCallArguments(context, parameters);
6733
+ includeCallArguments(context, interaction) {
6734
+ this.variable.includeCallArguments(context, interaction);
6503
6735
  }
6504
6736
  isPossibleTDZ() {
6505
6737
  // return cached value to avoid issues with the next tree-shaking pass
@@ -6582,11 +6814,40 @@ function closestParentFunctionOrProgram(node) {
6582
6814
  return node;
6583
6815
  }
6584
6816
 
6817
+ class ObjectMember extends ExpressionEntity {
6818
+ constructor(object, path) {
6819
+ super();
6820
+ this.object = object;
6821
+ this.path = path;
6822
+ }
6823
+ deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
6824
+ this.object.deoptimizeArgumentsOnInteractionAtPath(interaction, [...this.path, ...path], recursionTracker);
6825
+ }
6826
+ deoptimizePath(path) {
6827
+ this.object.deoptimizePath([...this.path, ...path]);
6828
+ }
6829
+ getLiteralValueAtPath(path, recursionTracker, origin) {
6830
+ return this.object.getLiteralValueAtPath([...this.path, ...path], recursionTracker, origin);
6831
+ }
6832
+ getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
6833
+ return this.object.getReturnExpressionWhenCalledAtPath([...this.path, ...path], interaction, recursionTracker, origin);
6834
+ }
6835
+ hasEffectsOnInteractionAtPath(path, interaction, context) {
6836
+ return this.object.hasEffectsOnInteractionAtPath([...this.path, ...path], interaction, context);
6837
+ }
6838
+ }
6839
+
6585
6840
  class Identifier extends IdentifierBase {
6586
6841
  constructor() {
6587
6842
  super(...arguments);
6588
6843
  this.variable = null;
6589
6844
  }
6845
+ get isDestructuringDeoptimized() {
6846
+ return isFlagSet(this.flags, 16777216 /* Flag.destructuringDeoptimized */);
6847
+ }
6848
+ set isDestructuringDeoptimized(value) {
6849
+ this.flags = setFlag(this.flags, 16777216 /* Flag.destructuringDeoptimized */, value);
6850
+ }
6590
6851
  addExportedVariables(variables, exportNamesByVariable) {
6591
6852
  if (exportNamesByVariable.has(this.variable)) {
6592
6853
  variables.push(this.variable);
@@ -6598,44 +6859,54 @@ class Identifier extends IdentifierBase {
6598
6859
  this.variable.addReference(this);
6599
6860
  this.isVariableReference = true;
6600
6861
  }
6601
- }
6602
- declare(kind, init) {
6603
- let variable;
6604
- const { treeshake } = this.scope.context.options;
6605
- switch (kind) {
6606
- case 'var': {
6607
- variable = this.scope.addDeclaration(this, this.scope.context, init, kind);
6608
- if (treeshake && treeshake.correctVarValueBeforeDeclaration) {
6609
- // Necessary to make sure the init is deoptimized. We cannot call deoptimizePath here.
6610
- variable.markInitializersForDeoptimization();
6611
- }
6612
- break;
6613
- }
6614
- case 'function': {
6615
- // in strict mode, functions are only hoisted within a scope but not across block scopes
6616
- variable = this.scope.addDeclaration(this, this.scope.context, init, kind);
6617
- break;
6618
- }
6619
- case 'let':
6620
- case 'const':
6621
- case 'using':
6622
- case 'await using':
6623
- case 'class': {
6624
- variable = this.scope.addDeclaration(this, this.scope.context, init, kind);
6625
- break;
6626
- }
6627
- case 'parameter': {
6628
- variable = this.scope.addParameterDeclaration(this);
6629
- break;
6630
- }
6631
- /* istanbul ignore next */
6632
- default: {
6633
- /* istanbul ignore next */
6634
- throw new Error(`Internal Error: Unexpected identifier kind ${kind}.`);
6862
+ }
6863
+ declare(kind, destructuredInitPath, init) {
6864
+ let variable;
6865
+ const { treeshake } = this.scope.context.options;
6866
+ if (kind === 'parameter') {
6867
+ variable = this.scope.addParameterDeclaration(this, destructuredInitPath);
6868
+ }
6869
+ else {
6870
+ variable = this.scope.addDeclaration(this, this.scope.context, init, destructuredInitPath, kind);
6871
+ if (kind === 'var' && treeshake && treeshake.correctVarValueBeforeDeclaration) {
6872
+ // Necessary to make sure the init is deoptimized. We cannot call deoptimizePath here.
6873
+ variable.markInitializersForDeoptimization();
6635
6874
  }
6636
6875
  }
6637
6876
  return [(this.variable = variable)];
6638
6877
  }
6878
+ deoptimizeAssignment(destructuredInitPath, init) {
6879
+ this.deoptimizePath(EMPTY_PATH);
6880
+ init.deoptimizePath([...destructuredInitPath, UnknownKey]);
6881
+ }
6882
+ hasEffectsWhenDestructuring(context, destructuredInitPath, init) {
6883
+ return (destructuredInitPath.length > 0 &&
6884
+ init.hasEffectsOnInteractionAtPath(destructuredInitPath, NODE_INTERACTION_UNKNOWN_ACCESS, context));
6885
+ }
6886
+ includeDestructuredIfNecessary(context, destructuredInitPath, init) {
6887
+ if (destructuredInitPath.length > 0 && !this.isDestructuringDeoptimized) {
6888
+ this.isDestructuringDeoptimized = true;
6889
+ init.deoptimizeArgumentsOnInteractionAtPath({
6890
+ args: [new ObjectMember(init, destructuredInitPath.slice(0, -1))],
6891
+ type: INTERACTION_ACCESSED
6892
+ }, destructuredInitPath, SHARED_RECURSION_TRACKER);
6893
+ }
6894
+ const { propertyReadSideEffects } = this.scope.context.options
6895
+ .treeshake;
6896
+ if ((this.included ||=
6897
+ destructuredInitPath.length > 0 &&
6898
+ !context.brokenFlow &&
6899
+ propertyReadSideEffects &&
6900
+ (propertyReadSideEffects === 'always' ||
6901
+ init.hasEffectsOnInteractionAtPath(destructuredInitPath, NODE_INTERACTION_UNKNOWN_ACCESS, createHasEffectsContext())))) {
6902
+ if (this.variable && !this.variable.included) {
6903
+ this.scope.context.includeVariableInModule(this.variable, EMPTY_PATH, context);
6904
+ }
6905
+ init.includePath(destructuredInitPath, context);
6906
+ return true;
6907
+ }
6908
+ return false;
6909
+ }
6639
6910
  markDeclarationReached() {
6640
6911
  this.variable.initReached = true;
6641
6912
  }
@@ -6688,18 +6959,17 @@ class Scope {
6688
6959
  - then the variable is still declared in the hoisted outer scope, but the initializer is assigned to the parameter
6689
6960
  - const, let, class, and function except in the cases above cannot redeclare anything
6690
6961
  */
6691
- addDeclaration(identifier, context, init, kind) {
6962
+ addDeclaration(identifier, context, init, destructuredInitPath, kind) {
6692
6963
  const name = identifier.name;
6693
6964
  const existingVariable = this.hoistedVariables?.get(name) || this.variables.get(name);
6694
6965
  if (existingVariable) {
6695
- const existingKind = existingVariable.kind;
6696
- if (kind === 'var' && existingKind === 'var') {
6966
+ if (kind === 'var' && existingVariable.kind === 'var') {
6697
6967
  existingVariable.addDeclaration(identifier, init);
6698
6968
  return existingVariable;
6699
6969
  }
6700
6970
  context.error(parseAst_js.logRedeclarationError(name), identifier.start);
6701
6971
  }
6702
- const newVariable = new LocalVariable(identifier.name, identifier, init, context, kind);
6972
+ const newVariable = new LocalVariable(identifier.name, identifier, init, destructuredInitPath, context, kind);
6703
6973
  this.variables.set(name, newVariable);
6704
6974
  return newVariable;
6705
6975
  }
@@ -6875,7 +7145,6 @@ class MethodBase extends NodeBase {
6875
7145
  }
6876
7146
  return this.getAccessedValue()[0].hasEffectsOnInteractionAtPath(path, interaction, context);
6877
7147
  }
6878
- applyDeoptimizations() { }
6879
7148
  getAccessedValue() {
6880
7149
  if (this.accessedValue === null) {
6881
7150
  if (this.kind === 'get') {
@@ -6889,19 +7158,20 @@ class MethodBase extends NodeBase {
6889
7158
  return this.accessedValue;
6890
7159
  }
6891
7160
  }
7161
+ MethodBase.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
7162
+ MethodBase.prototype.applyDeoptimizations = doNotDeoptimize;
6892
7163
 
6893
7164
  class MethodDefinition extends MethodBase {
6894
7165
  hasEffects(context) {
6895
7166
  return super.hasEffects(context) || checkEffectForNodes(this.decorators, context);
6896
7167
  }
6897
- applyDeoptimizations() { }
6898
7168
  }
6899
7169
 
6900
7170
  class BlockScope extends ChildScope {
6901
7171
  constructor(parent) {
6902
7172
  super(parent, parent.context);
6903
7173
  }
6904
- addDeclaration(identifier, context, init, kind) {
7174
+ addDeclaration(identifier, context, init, destructuredInitPath, kind) {
6905
7175
  if (kind === 'var') {
6906
7176
  const name = identifier.name;
6907
7177
  const existingVariable = this.hoistedVariables?.get(name) || this.variables.get(name);
@@ -6913,7 +7183,7 @@ class BlockScope extends ChildScope {
6913
7183
  }
6914
7184
  return context.error(parseAst_js.logRedeclarationError(name), identifier.start);
6915
7185
  }
6916
- const declaredVariable = this.parent.addDeclaration(identifier, context, init, kind);
7186
+ const declaredVariable = this.parent.addDeclaration(identifier, context, init, destructuredInitPath, kind);
6917
7187
  // Necessary to make sure the init is deoptimized for conditional declarations.
6918
7188
  // We cannot call deoptimizePath here.
6919
7189
  declaredVariable.markInitializersForDeoptimization();
@@ -6921,7 +7191,7 @@ class BlockScope extends ChildScope {
6921
7191
  this.addHoistedVariable(name, declaredVariable);
6922
7192
  return declaredVariable;
6923
7193
  }
6924
- return super.addDeclaration(identifier, context, init, kind);
7194
+ return super.addDeclaration(identifier, context, init, destructuredInitPath, kind);
6925
7195
  }
6926
7196
  }
6927
7197
 
@@ -6953,33 +7223,12 @@ class StaticBlock extends NodeBase {
6953
7223
  }
6954
7224
  }
6955
7225
  }
7226
+ StaticBlock.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
7227
+ StaticBlock.prototype.applyDeoptimizations = doNotDeoptimize;
6956
7228
  function isStaticBlock(statement) {
6957
7229
  return statement.type === parseAst_js.StaticBlock;
6958
7230
  }
6959
7231
 
6960
- class ObjectMember extends ExpressionEntity {
6961
- constructor(object, key) {
6962
- super();
6963
- this.object = object;
6964
- this.key = key;
6965
- }
6966
- deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
6967
- this.object.deoptimizeArgumentsOnInteractionAtPath(interaction, [this.key, ...path], recursionTracker);
6968
- }
6969
- deoptimizePath(path) {
6970
- this.object.deoptimizePath([this.key, ...path]);
6971
- }
6972
- getLiteralValueAtPath(path, recursionTracker, origin) {
6973
- return this.object.getLiteralValueAtPath([this.key, ...path], recursionTracker, origin);
6974
- }
6975
- getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
6976
- return this.object.getReturnExpressionWhenCalledAtPath([this.key, ...path], interaction, recursionTracker, origin);
6977
- }
6978
- hasEffectsOnInteractionAtPath(path, interaction, context) {
6979
- return this.object.hasEffectsOnInteractionAtPath([this.key, ...path], interaction, context);
6980
- }
6981
- }
6982
-
6983
7232
  class ClassNode extends NodeBase {
6984
7233
  constructor() {
6985
7234
  super(...arguments);
@@ -7020,21 +7269,20 @@ class ClassNode extends NodeBase {
7020
7269
  : this.getObjectEntity().hasEffectsOnInteractionAtPath(path, interaction, context);
7021
7270
  }
7022
7271
  include(context, includeChildrenRecursively) {
7023
- if (!this.deoptimized)
7024
- this.applyDeoptimizations();
7025
- this.included = true;
7272
+ if (!this.included)
7273
+ this.includeNode(context);
7026
7274
  this.superClass?.include(context, includeChildrenRecursively);
7027
7275
  this.body.include(context, includeChildrenRecursively);
7028
7276
  for (const decorator of this.decorators)
7029
7277
  decorator.include(context, includeChildrenRecursively);
7030
7278
  if (this.id) {
7031
7279
  this.id.markDeclarationReached();
7032
- this.id.include();
7280
+ this.id.include(context);
7033
7281
  }
7034
7282
  }
7035
7283
  initialise() {
7036
7284
  super.initialise();
7037
- this.id?.declare('class', this);
7285
+ this.id?.declare('class', EMPTY_PATH, this);
7038
7286
  for (const method of this.body.body) {
7039
7287
  if (method instanceof MethodDefinition && method.kind === 'constructor') {
7040
7288
  this.classConstructor = method;
@@ -7092,11 +7340,12 @@ class ClassNode extends NodeBase {
7092
7340
  staticProperties.unshift({
7093
7341
  key: 'prototype',
7094
7342
  kind: 'init',
7095
- property: new ObjectEntity(dynamicMethods, this.superClass ? new ObjectMember(this.superClass, 'prototype') : OBJECT_PROTOTYPE)
7343
+ property: new ObjectEntity(dynamicMethods, this.superClass ? new ObjectMember(this.superClass, ['prototype']) : OBJECT_PROTOTYPE)
7096
7344
  });
7097
7345
  return (this.objectEntity = new ObjectEntity(staticProperties, this.superClass || OBJECT_PROTOTYPE));
7098
7346
  }
7099
7347
  }
7348
+ ClassNode.prototype.includeNode = onlyIncludeSelf;
7100
7349
 
7101
7350
  class ClassDeclaration extends ClassNode {
7102
7351
  initialise() {
@@ -7149,53 +7398,60 @@ class ClassDeclaration extends ClassNode {
7149
7398
 
7150
7399
  class ArgumentsVariable extends LocalVariable {
7151
7400
  constructor(context) {
7152
- super('arguments', null, UNKNOWN_EXPRESSION, context, 'other');
7153
- this.deoptimizedArguments = [];
7401
+ super('arguments', null, UNKNOWN_EXPRESSION, EMPTY_PATH, context, 'other');
7154
7402
  }
7155
- addArgumentToBeDeoptimized(argument) {
7156
- if (this.included) {
7157
- argument.deoptimizePath(UNKNOWN_PATH);
7158
- }
7159
- else {
7160
- this.deoptimizedArguments.push(argument);
7161
- }
7403
+ addArgumentToBeDeoptimized(_argument) { }
7404
+ // Only If there is at least one reference, then we need to track all
7405
+ // arguments in order to be able to deoptimize them.
7406
+ addReference() {
7407
+ this.deoptimizedArguments = [];
7408
+ this.addArgumentToBeDeoptimized = addArgumentToBeDeoptimized;
7162
7409
  }
7163
7410
  hasEffectsOnInteractionAtPath(path, { type }) {
7164
7411
  return type !== INTERACTION_ACCESSED || path.length > 1;
7165
7412
  }
7166
- include() {
7167
- super.include();
7413
+ includePath(path, context) {
7414
+ super.includePath(path, context);
7168
7415
  for (const argument of this.deoptimizedArguments) {
7169
7416
  argument.deoptimizePath(UNKNOWN_PATH);
7170
7417
  }
7171
7418
  this.deoptimizedArguments.length = 0;
7172
7419
  }
7173
7420
  }
7421
+ function addArgumentToBeDeoptimized(argument) {
7422
+ if (this.included) {
7423
+ argument.deoptimizePath(UNKNOWN_PATH);
7424
+ }
7425
+ else {
7426
+ this.deoptimizedArguments?.push(argument);
7427
+ }
7428
+ }
7174
7429
 
7175
7430
  const MAX_TRACKED_INTERACTIONS = 20;
7176
7431
  const NO_INTERACTIONS = parseAst_js.EMPTY_ARRAY;
7177
7432
  const UNKNOWN_DEOPTIMIZED_FIELD = new Set([UnknownKey]);
7178
- const EMPTY_PATH_TRACKER = new PathTracker();
7433
+ const EMPTY_PATH_TRACKER = new EntityPathTracker();
7179
7434
  const UNKNOWN_DEOPTIMIZED_ENTITY = new Set([UNKNOWN_EXPRESSION]);
7180
7435
  class ParameterVariable extends LocalVariable {
7181
- constructor(name, declarator, context) {
7182
- super(name, declarator, UNKNOWN_EXPRESSION, context, 'parameter');
7436
+ constructor(name, declarator, argumentPath, context) {
7437
+ super(name, declarator, UNKNOWN_EXPRESSION, argumentPath, context, 'parameter');
7438
+ this.includedPathTracker = new IncludedTopLevelPathTracker();
7439
+ this.argumentsToBeDeoptimized = new Set();
7183
7440
  this.deoptimizationInteractions = [];
7184
- this.deoptimizations = new PathTracker();
7441
+ this.deoptimizations = new EntityPathTracker();
7185
7442
  this.deoptimizedFields = new Set();
7186
- this.entitiesToBeDeoptimized = new Set();
7187
- this.expressionsUseTheKnownValue = [];
7443
+ this.expressionsDependingOnKnownValue = [];
7188
7444
  this.knownValue = null;
7189
7445
  this.knownValueLiteral = UnknownValue;
7190
- this.frozenValue = null;
7191
7446
  }
7192
- addEntityToBeDeoptimized(entity) {
7447
+ addArgumentValue(entity) {
7448
+ this.updateKnownValue(entity);
7193
7449
  if (entity === UNKNOWN_EXPRESSION) {
7194
7450
  // As unknown expressions fully deoptimize all interactions, we can clear
7195
7451
  // the interaction cache at this point provided we keep this optimization
7196
7452
  // in mind when adding new interactions
7197
- if (!this.entitiesToBeDeoptimized.has(UNKNOWN_EXPRESSION)) {
7198
- this.entitiesToBeDeoptimized.add(UNKNOWN_EXPRESSION);
7453
+ if (!this.argumentsToBeDeoptimized.has(UNKNOWN_EXPRESSION)) {
7454
+ this.argumentsToBeDeoptimized.add(UNKNOWN_EXPRESSION);
7199
7455
  for (const { interaction } of this.deoptimizationInteractions) {
7200
7456
  deoptimizeInteraction(interaction);
7201
7457
  }
@@ -7205,27 +7461,30 @@ class ParameterVariable extends LocalVariable {
7205
7461
  else if (this.deoptimizedFields.has(UnknownKey)) {
7206
7462
  // This means that we already deoptimized all interactions and no longer
7207
7463
  // track them
7208
- entity.deoptimizePath(UNKNOWN_PATH);
7464
+ entity.deoptimizePath([...this.initPath, UnknownKey]);
7209
7465
  }
7210
- else if (!this.entitiesToBeDeoptimized.has(entity)) {
7211
- this.entitiesToBeDeoptimized.add(entity);
7466
+ else if (!this.argumentsToBeDeoptimized.has(entity)) {
7467
+ this.argumentsToBeDeoptimized.add(entity);
7212
7468
  for (const field of this.deoptimizedFields) {
7213
- entity.deoptimizePath([field]);
7469
+ entity.deoptimizePath([...this.initPath, field]);
7214
7470
  }
7215
7471
  for (const { interaction, path } of this.deoptimizationInteractions) {
7216
- entity.deoptimizeArgumentsOnInteractionAtPath(interaction, path, SHARED_RECURSION_TRACKER);
7472
+ entity.deoptimizeArgumentsOnInteractionAtPath(interaction, [...this.initPath, ...path], SHARED_RECURSION_TRACKER);
7217
7473
  }
7218
7474
  }
7219
7475
  }
7476
+ /** This says we should not make assumptions about the value of the parameter.
7477
+ * This is different from deoptimization that will also cause argument values
7478
+ * to be deoptimized. */
7220
7479
  markReassigned() {
7221
7480
  if (this.isReassigned) {
7222
7481
  return;
7223
7482
  }
7224
7483
  super.markReassigned();
7225
- for (const expression of this.expressionsUseTheKnownValue) {
7484
+ for (const expression of this.expressionsDependingOnKnownValue) {
7226
7485
  expression.deoptimizeCache();
7227
7486
  }
7228
- this.expressionsUseTheKnownValue = parseAst_js.EMPTY_ARRAY;
7487
+ this.expressionsDependingOnKnownValue = parseAst_js.EMPTY_ARRAY;
7229
7488
  }
7230
7489
  deoptimizeCache() {
7231
7490
  this.markReassigned();
@@ -7242,7 +7501,7 @@ class ParameterVariable extends LocalVariable {
7242
7501
  }
7243
7502
  if (this.knownValue === null) {
7244
7503
  this.knownValue = argument;
7245
- this.knownValueLiteral = argument.getLiteralValueAtPath(EMPTY_PATH, SHARED_RECURSION_TRACKER, this);
7504
+ this.knownValueLiteral = argument.getLiteralValueAtPath(this.initPath, SHARED_RECURSION_TRACKER, this);
7246
7505
  return;
7247
7506
  }
7248
7507
  // the same literal or identifier, do nothing
@@ -7252,14 +7511,10 @@ class ParameterVariable extends LocalVariable {
7252
7511
  this.knownValue.variable === argument.variable)) {
7253
7512
  return;
7254
7513
  }
7255
- const oldValue = this.knownValueLiteral;
7256
- if (typeof oldValue === 'symbol') {
7257
- this.markReassigned();
7258
- return;
7259
- }
7260
- // add tracking for the new argument
7261
- const newValue = argument.getLiteralValueAtPath(EMPTY_PATH, SHARED_RECURSION_TRACKER, this);
7262
- if (newValue !== oldValue) {
7514
+ const { knownValueLiteral } = this;
7515
+ if (typeof knownValueLiteral === 'symbol' ||
7516
+ argument.getLiteralValueAtPath(this.initPath, SHARED_RECURSION_TRACKER, this) !==
7517
+ knownValueLiteral) {
7263
7518
  this.markReassigned();
7264
7519
  }
7265
7520
  }
@@ -7270,42 +7525,47 @@ class ParameterVariable extends LocalVariable {
7270
7525
  * @returns the frozen value
7271
7526
  */
7272
7527
  getKnownValue() {
7273
- if (this.frozenValue === null) {
7274
- this.frozenValue = this.knownValue || UNKNOWN_EXPRESSION;
7275
- }
7276
- return this.frozenValue;
7528
+ return this.knownValue || UNKNOWN_EXPRESSION;
7277
7529
  }
7278
7530
  getLiteralValueAtPath(path, recursionTracker, origin) {
7279
- if (this.isReassigned) {
7531
+ if (this.isReassigned || path.length + this.initPath.length > MAX_PATH_DEPTH) {
7280
7532
  return UnknownValue;
7281
7533
  }
7282
7534
  const knownValue = this.getKnownValue();
7283
- this.expressionsUseTheKnownValue.push(origin);
7284
- return recursionTracker.withTrackedEntityAtPath(path, knownValue, () => knownValue.getLiteralValueAtPath(path, recursionTracker, origin), UnknownValue);
7535
+ this.expressionsDependingOnKnownValue.push(origin);
7536
+ return recursionTracker.withTrackedEntityAtPath(path, knownValue, () => knownValue.getLiteralValueAtPath([...this.initPath, ...path], recursionTracker, origin), UnknownValue);
7285
7537
  }
7286
7538
  hasEffectsOnInteractionAtPath(path, interaction, context) {
7287
- if (this.isReassigned || interaction.type === INTERACTION_ASSIGNED) {
7539
+ const { type } = interaction;
7540
+ if (this.isReassigned ||
7541
+ type === INTERACTION_ASSIGNED ||
7542
+ path.length + this.initPath.length > MAX_PATH_DEPTH) {
7288
7543
  return super.hasEffectsOnInteractionAtPath(path, interaction, context);
7289
7544
  }
7290
- const knownValue = this.getKnownValue();
7291
- return knownValue.hasEffectsOnInteractionAtPath(path, interaction, context);
7545
+ return (!(type === INTERACTION_CALLED
7546
+ ? (interaction.withNew
7547
+ ? context.instantiated
7548
+ : context.called).trackEntityAtPathAndGetIfTracked(path, interaction.args, this)
7549
+ : context.accessed.trackEntityAtPathAndGetIfTracked(path, this)) &&
7550
+ this.getKnownValue().hasEffectsOnInteractionAtPath([...this.initPath, ...path], interaction, context));
7292
7551
  }
7293
7552
  deoptimizeArgumentsOnInteractionAtPath(interaction, path) {
7294
7553
  // For performance reasons, we fully deoptimize all deeper interactions
7295
7554
  if (path.length >= 2 ||
7296
- this.entitiesToBeDeoptimized.has(UNKNOWN_EXPRESSION) ||
7555
+ this.argumentsToBeDeoptimized.has(UNKNOWN_EXPRESSION) ||
7297
7556
  this.deoptimizationInteractions.length >= MAX_TRACKED_INTERACTIONS ||
7298
7557
  (path.length === 1 &&
7299
7558
  (this.deoptimizedFields.has(UnknownKey) ||
7300
- (interaction.type === INTERACTION_CALLED && this.deoptimizedFields.has(path[0]))))) {
7559
+ (interaction.type === INTERACTION_CALLED && this.deoptimizedFields.has(path[0])))) ||
7560
+ this.initPath.length + path.length > MAX_PATH_DEPTH) {
7301
7561
  deoptimizeInteraction(interaction);
7302
7562
  return;
7303
7563
  }
7304
7564
  if (!this.deoptimizations.trackEntityAtPathAndGetIfTracked(path, interaction.args)) {
7305
- for (const entity of this.entitiesToBeDeoptimized) {
7306
- entity.deoptimizeArgumentsOnInteractionAtPath(interaction, path, SHARED_RECURSION_TRACKER);
7565
+ for (const entity of this.argumentsToBeDeoptimized) {
7566
+ entity.deoptimizeArgumentsOnInteractionAtPath(interaction, [...this.initPath, ...path], SHARED_RECURSION_TRACKER);
7307
7567
  }
7308
- if (!this.entitiesToBeDeoptimized.has(UNKNOWN_EXPRESSION)) {
7568
+ if (!this.argumentsToBeDeoptimized.has(UNKNOWN_EXPRESSION)) {
7309
7569
  this.deoptimizationInteractions.push({
7310
7570
  interaction,
7311
7571
  path
@@ -7326,17 +7586,17 @@ class ParameterVariable extends LocalVariable {
7326
7586
  return;
7327
7587
  }
7328
7588
  this.deoptimizedFields.add(key);
7329
- for (const entity of this.entitiesToBeDeoptimized) {
7589
+ for (const entity of this.argumentsToBeDeoptimized) {
7330
7590
  // We do not need a recursion tracker here as we already track whether
7331
7591
  // this field is deoptimized
7332
- entity.deoptimizePath([key]);
7592
+ entity.deoptimizePath([...this.initPath, key]);
7333
7593
  }
7334
7594
  if (key === UnknownKey) {
7335
7595
  // save some memory
7336
7596
  this.deoptimizationInteractions = NO_INTERACTIONS;
7337
7597
  this.deoptimizations = EMPTY_PATH_TRACKER;
7338
7598
  this.deoptimizedFields = UNKNOWN_DEOPTIMIZED_FIELD;
7339
- this.entitiesToBeDeoptimized = UNKNOWN_DEOPTIMIZED_ENTITY;
7599
+ this.argumentsToBeDeoptimized = UNKNOWN_DEOPTIMIZED_ENTITY;
7340
7600
  }
7341
7601
  }
7342
7602
  getReturnExpressionWhenCalledAtPath(path) {
@@ -7351,11 +7611,14 @@ class ParameterVariable extends LocalVariable {
7351
7611
  }
7352
7612
  return UNKNOWN_RETURN_EXPRESSION;
7353
7613
  }
7614
+ includeArgumentPaths(entity, context) {
7615
+ this.includedPathTracker.includeAllPaths(entity, context, this.initPath);
7616
+ }
7354
7617
  }
7355
7618
 
7356
7619
  class ThisVariable extends ParameterVariable {
7357
7620
  constructor(context) {
7358
- super('this', null, context);
7621
+ super('this', null, EMPTY_PATH, context);
7359
7622
  }
7360
7623
  hasEffectsOnInteractionAtPath(path, interaction, context) {
7361
7624
  return (context.replacedVariableInits.get(this) || UNKNOWN_EXPRESSION).hasEffectsOnInteractionAtPath(path, interaction, context);
@@ -7367,7 +7630,7 @@ class CatchBodyScope extends ChildScope {
7367
7630
  super(parent, parent.context);
7368
7631
  this.parent = parent;
7369
7632
  }
7370
- addDeclaration(identifier, context, init, kind) {
7633
+ addDeclaration(identifier, context, init, destructuredInitPath, kind) {
7371
7634
  if (kind === 'var') {
7372
7635
  const name = identifier.name;
7373
7636
  const existingVariable = this.hoistedVariables?.get(name) || this.variables.get(name);
@@ -7380,7 +7643,7 @@ class CatchBodyScope extends ChildScope {
7380
7643
  // the assignment actually goes to the parameter and the var is
7381
7644
  // hoisted without assignment. Locally, it is shadowed by the
7382
7645
  // parameter
7383
- const declaredVariable = this.parent.parent.addDeclaration(identifier, context, UNDEFINED_EXPRESSION, kind);
7646
+ const declaredVariable = this.parent.parent.addDeclaration(identifier, context, UNDEFINED_EXPRESSION, destructuredInitPath, kind);
7384
7647
  // To avoid the need to rewrite the declaration, we link the variable
7385
7648
  // names. If we ever implement a logic that splits initialization and
7386
7649
  // assignment for hoisted vars, the "renderLikeHoisted" logic can be
@@ -7399,7 +7662,7 @@ class CatchBodyScope extends ChildScope {
7399
7662
  return context.error(parseAst_js.logRedeclarationError(name), identifier.start);
7400
7663
  }
7401
7664
  // We only add parameters to parameter scopes
7402
- const declaredVariable = this.parent.parent.addDeclaration(identifier, context, init, kind);
7665
+ const declaredVariable = this.parent.parent.addDeclaration(identifier, context, init, destructuredInitPath, kind);
7403
7666
  // Necessary to make sure the init is deoptimized for conditional declarations.
7404
7667
  // We cannot call deoptimizePath here.
7405
7668
  declaredVariable.markInitializersForDeoptimization();
@@ -7407,7 +7670,7 @@ class CatchBodyScope extends ChildScope {
7407
7670
  this.addHoistedVariable(name, declaredVariable);
7408
7671
  return declaredVariable;
7409
7672
  }
7410
- return super.addDeclaration(identifier, context, init, kind);
7673
+ return super.addDeclaration(identifier, context, init, destructuredInitPath, kind);
7411
7674
  }
7412
7675
  }
7413
7676
 
@@ -7417,7 +7680,7 @@ class FunctionBodyScope extends ChildScope {
7417
7680
  }
7418
7681
  // There is stuff that is only allowed in function scopes, i.e. functions can
7419
7682
  // be redeclared, functions and var can redeclare each other
7420
- addDeclaration(identifier, context, init, kind) {
7683
+ addDeclaration(identifier, context, init, destructuredInitPath, kind) {
7421
7684
  const name = identifier.name;
7422
7685
  const existingVariable = this.hoistedVariables?.get(name) || this.variables.get(name);
7423
7686
  if (existingVariable) {
@@ -7429,7 +7692,7 @@ class FunctionBodyScope extends ChildScope {
7429
7692
  }
7430
7693
  context.error(parseAst_js.logRedeclarationError(name), identifier.start);
7431
7694
  }
7432
- const newVariable = new LocalVariable(identifier.name, identifier, init, context, kind);
7695
+ const newVariable = new LocalVariable(identifier.name, identifier, init, destructuredInitPath, context, kind);
7433
7696
  this.variables.set(name, newVariable);
7434
7697
  return newVariable;
7435
7698
  }
@@ -7438,21 +7701,21 @@ class FunctionBodyScope extends ChildScope {
7438
7701
  class ParameterScope extends ChildScope {
7439
7702
  constructor(parent, isCatchScope) {
7440
7703
  super(parent, parent.context);
7441
- this.parameters = [];
7442
7704
  this.hasRest = false;
7705
+ this.parameters = [];
7443
7706
  this.bodyScope = isCatchScope ? new CatchBodyScope(this) : new FunctionBodyScope(this);
7444
7707
  }
7445
7708
  /**
7446
7709
  * Adds a parameter to this scope. Parameters must be added in the correct
7447
7710
  * order, i.e. from left to right.
7448
7711
  */
7449
- addParameterDeclaration(identifier) {
7712
+ addParameterDeclaration(identifier, argumentPath) {
7450
7713
  const { name, start } = identifier;
7451
7714
  const existingParameter = this.variables.get(name);
7452
7715
  if (existingParameter) {
7453
7716
  return this.context.error(parseAst_js.logDuplicateArgumentNameError(name), start);
7454
7717
  }
7455
- const variable = new ParameterVariable(name, identifier, this.context);
7718
+ const variable = new ParameterVariable(name, identifier, argumentPath, this.context);
7456
7719
  this.variables.set(name, variable);
7457
7720
  // We also add it to the body scope to detect name conflicts with local
7458
7721
  // variables. We still need the intermediate scope, though, as parameter
@@ -7470,42 +7733,56 @@ class ParameterScope extends ChildScope {
7470
7733
  }
7471
7734
  this.hasRest = hasRest;
7472
7735
  }
7473
- includeCallArguments(context, parameters) {
7736
+ includeCallArguments(context, interaction) {
7474
7737
  let calledFromTryStatement = false;
7475
7738
  let argumentIncluded = false;
7476
7739
  const restParameter = this.hasRest && this.parameters[this.parameters.length - 1];
7477
- for (const checkedArgument of parameters) {
7478
- if (checkedArgument instanceof SpreadElement) {
7479
- for (const argument of parameters) {
7480
- argument.include(context, false);
7481
- }
7482
- break;
7740
+ const { args } = interaction;
7741
+ let lastExplicitlyIncludedIndex = args.length - 1;
7742
+ // If there is a SpreadElement, we need to include all arguments after it
7743
+ // because we no longer know which argument corresponds to which parameter.
7744
+ for (let argumentIndex = 1; argumentIndex < args.length; argumentIndex++) {
7745
+ const argument = args[argumentIndex];
7746
+ if (argument instanceof SpreadElement && !argumentIncluded) {
7747
+ argumentIncluded = true;
7748
+ lastExplicitlyIncludedIndex = argumentIndex - 1;
7749
+ }
7750
+ if (argumentIncluded) {
7751
+ argument.includePath(UNKNOWN_PATH, context);
7752
+ argument.include(context, false);
7483
7753
  }
7484
7754
  }
7485
- for (let index = parameters.length - 1; index >= 0; index--) {
7486
- const parameterVariables = this.parameters[index] || restParameter;
7487
- const argument = parameters[index];
7755
+ // Now we go backwards either starting from the last argument or before the
7756
+ // first SpreadElement to ensure all arguments before are included as needed
7757
+ for (let index = lastExplicitlyIncludedIndex; index >= 1; index--) {
7758
+ const parameterVariables = this.parameters[index - 1] || restParameter;
7759
+ const argument = args[index];
7488
7760
  if (parameterVariables) {
7489
7761
  calledFromTryStatement = false;
7490
7762
  if (parameterVariables.length === 0) {
7491
- // handle empty destructuring
7763
+ // handle empty destructuring to avoid destructuring undefined
7492
7764
  argumentIncluded = true;
7493
7765
  }
7494
7766
  else {
7495
- for (const variable of parameterVariables) {
7496
- if (variable.included) {
7497
- argumentIncluded = true;
7498
- }
7499
- if (variable.calledFromTryStatement) {
7767
+ for (const parameterVariable of parameterVariables) {
7768
+ if (parameterVariable.calledFromTryStatement) {
7500
7769
  calledFromTryStatement = true;
7501
7770
  }
7771
+ if (parameterVariable.included) {
7772
+ argumentIncluded = true;
7773
+ if (calledFromTryStatement) {
7774
+ argument.include(context, true);
7775
+ }
7776
+ else {
7777
+ parameterVariable.includeArgumentPaths(argument, context);
7778
+ argument.include(context, false);
7779
+ }
7780
+ }
7502
7781
  }
7503
7782
  }
7504
7783
  }
7505
- if (!argumentIncluded && argument.shouldBeIncluded(context)) {
7784
+ if (!argument.included && (argumentIncluded || argument.shouldBeIncluded(context))) {
7506
7785
  argumentIncluded = true;
7507
- }
7508
- if (argumentIncluded) {
7509
7786
  argument.include(context, calledFromTryStatement);
7510
7787
  }
7511
7788
  }
@@ -7521,11 +7798,62 @@ class ReturnValueScope extends ParameterScope {
7521
7798
  addReturnExpression(expression) {
7522
7799
  this.returnExpressions.push(expression);
7523
7800
  }
7801
+ deoptimizeArgumentsOnCall(interaction) {
7802
+ const { parameters } = this;
7803
+ const { args } = interaction;
7804
+ let position = 0;
7805
+ for (; position < args.length - 1; position++) {
7806
+ // Only the "this" argument arg[0] can be null
7807
+ const argument = args[position + 1];
7808
+ if (argument instanceof SpreadElement) {
7809
+ // This deoptimizes the current and remaining parameters and arguments
7810
+ for (; position < parameters.length; position++) {
7811
+ args[position + 1]?.deoptimizePath(UNKNOWN_PATH);
7812
+ parameters[position].forEach(variable => variable.markReassigned());
7813
+ }
7814
+ break;
7815
+ }
7816
+ if (this.hasRest && position >= parameters.length - 1) {
7817
+ argument.deoptimizePath(UNKNOWN_PATH);
7818
+ }
7819
+ else {
7820
+ const variables = parameters[position];
7821
+ if (variables) {
7822
+ for (const variable of variables) {
7823
+ variable.addArgumentValue(argument);
7824
+ }
7825
+ }
7826
+ this.addArgumentToBeDeoptimized(argument);
7827
+ }
7828
+ }
7829
+ const nonRestParameterLength = this.hasRest ? parameters.length - 1 : parameters.length;
7830
+ for (; position < nonRestParameterLength; position++) {
7831
+ for (const variable of parameters[position]) {
7832
+ variable.addArgumentValue(UNDEFINED_EXPRESSION);
7833
+ }
7834
+ }
7835
+ }
7524
7836
  getReturnExpression() {
7525
7837
  if (this.returnExpression === null)
7526
7838
  this.updateReturnExpression();
7527
7839
  return this.returnExpression;
7528
7840
  }
7841
+ deoptimizeAllParameters() {
7842
+ for (const parameter of this.parameters) {
7843
+ for (const variable of parameter) {
7844
+ variable.deoptimizePath(UNKNOWN_PATH);
7845
+ variable.markReassigned();
7846
+ }
7847
+ }
7848
+ }
7849
+ reassignAllParameters() {
7850
+ for (const parameter of this.parameters) {
7851
+ for (const variable of parameter) {
7852
+ variable.markReassigned();
7853
+ }
7854
+ }
7855
+ }
7856
+ addArgumentToBeDeoptimized(_argument) { }
7529
7857
  updateReturnExpression() {
7530
7858
  if (this.returnExpressions.length === 1) {
7531
7859
  this.returnExpression = this.returnExpressions[0];
@@ -7541,24 +7869,30 @@ class ReturnValueScope extends ParameterScope {
7541
7869
 
7542
7870
  class FunctionScope extends ReturnValueScope {
7543
7871
  constructor(parent) {
7544
- const { context } = parent;
7545
7872
  super(parent, false);
7873
+ const { context } = parent;
7546
7874
  this.variables.set('arguments', (this.argumentsVariable = new ArgumentsVariable(context)));
7547
7875
  this.variables.set('this', (this.thisVariable = new ThisVariable(context)));
7548
7876
  }
7549
7877
  findLexicalBoundary() {
7550
7878
  return this;
7551
7879
  }
7552
- includeCallArguments(context, parameters) {
7553
- super.includeCallArguments(context, parameters);
7880
+ includeCallArguments(context, interaction) {
7881
+ super.includeCallArguments(context, interaction);
7554
7882
  if (this.argumentsVariable.included) {
7555
- for (const argument of parameters) {
7556
- if (!argument.included) {
7883
+ const { args } = interaction;
7884
+ for (let argumentIndex = 1; argumentIndex < args.length; argumentIndex++) {
7885
+ const argument = args[argumentIndex];
7886
+ if (argument) {
7887
+ argument.includePath(UNKNOWN_PATH, context);
7557
7888
  argument.include(context, false);
7558
7889
  }
7559
7890
  }
7560
7891
  }
7561
7892
  }
7893
+ addArgumentToBeDeoptimized(argument) {
7894
+ this.argumentsVariable.addArgumentToBeDeoptimized(argument);
7895
+ }
7562
7896
  }
7563
7897
 
7564
7898
  class ExpressionStatement extends NodeBase {
@@ -7586,8 +7920,9 @@ class ExpressionStatement extends NodeBase {
7586
7920
  return this.parent.type !== parseAst_js.Program;
7587
7921
  return super.shouldBeIncluded(context);
7588
7922
  }
7589
- applyDeoptimizations() { }
7590
7923
  }
7924
+ ExpressionStatement.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
7925
+ ExpressionStatement.prototype.applyDeoptimizations = doNotDeoptimize;
7591
7926
 
7592
7927
  class BlockStatement extends NodeBase {
7593
7928
  get deoptimizeBody() {
@@ -7652,6 +7987,8 @@ class BlockStatement extends NodeBase {
7652
7987
  }
7653
7988
  }
7654
7989
  }
7990
+ BlockStatement.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
7991
+ BlockStatement.prototype.applyDeoptimizations = doNotDeoptimize;
7655
7992
 
7656
7993
  class RestElement extends NodeBase {
7657
7994
  constructor() {
@@ -7661,9 +7998,12 @@ class RestElement extends NodeBase {
7661
7998
  addExportedVariables(variables, exportNamesByVariable) {
7662
7999
  this.argument.addExportedVariables(variables, exportNamesByVariable);
7663
8000
  }
7664
- declare(kind, init) {
8001
+ declare(kind, destructuredInitPath, init) {
7665
8002
  this.declarationInit = init;
7666
- return this.argument.declare(kind, UNKNOWN_EXPRESSION);
8003
+ return this.argument.declare(kind, getIncludedPatternPath$1(destructuredInitPath), init);
8004
+ }
8005
+ deoptimizeAssignment(destructuredInitPath, init) {
8006
+ this.argument.deoptimizeAssignment(getIncludedPatternPath$1(destructuredInitPath), init);
7667
8007
  }
7668
8008
  deoptimizePath(path) {
7669
8009
  if (path.length === 0) {
@@ -7674,6 +8014,20 @@ class RestElement extends NodeBase {
7674
8014
  return (path.length > 0 ||
7675
8015
  this.argument.hasEffectsOnInteractionAtPath(EMPTY_PATH, interaction, context));
7676
8016
  }
8017
+ hasEffectsWhenDestructuring(context, destructuredInitPath, init) {
8018
+ return this.argument.hasEffectsWhenDestructuring(context, getIncludedPatternPath$1(destructuredInitPath), init);
8019
+ }
8020
+ includeDestructuredIfNecessary(context, destructuredInitPath, init) {
8021
+ return (this.included =
8022
+ this.argument.includeDestructuredIfNecessary(context, getIncludedPatternPath$1(destructuredInitPath), init) || this.included);
8023
+ }
8024
+ include(context, includeChildrenRecursively) {
8025
+ if (!this.included)
8026
+ this.includeNode(context);
8027
+ // This should just include the identifier, its properties should be
8028
+ // included where the variable is used.
8029
+ this.argument.include(context, includeChildrenRecursively);
8030
+ }
7677
8031
  markDeclarationReached() {
7678
8032
  this.argument.markDeclarationReached();
7679
8033
  }
@@ -7685,12 +8039,16 @@ class RestElement extends NodeBase {
7685
8039
  }
7686
8040
  }
7687
8041
  }
8042
+ RestElement.prototype.includeNode = onlyIncludeSelf;
8043
+ const getIncludedPatternPath$1 = (destructuredInitPath) => destructuredInitPath.at(-1) === UnknownKey
8044
+ ? destructuredInitPath
8045
+ : [...destructuredInitPath, UnknownKey];
7688
8046
 
7689
8047
  class FunctionBase extends NodeBase {
7690
8048
  constructor() {
7691
8049
  super(...arguments);
7692
- this.objectEntity = null;
7693
8050
  this.parameterVariableValuesDeoptimized = false;
8051
+ this.includeCallArguments = this.scope.includeCallArguments.bind(this.scope);
7694
8052
  }
7695
8053
  get async() {
7696
8054
  return isFlagSet(this.flags, 256 /* Flag.async */);
@@ -7710,53 +8068,15 @@ class FunctionBase extends NodeBase {
7710
8068
  set generator(value) {
7711
8069
  this.flags = setFlag(this.flags, 4194304 /* Flag.generator */, value);
7712
8070
  }
7713
- updateParameterVariableValues(_arguments) {
7714
- for (let position = 0; position < this.params.length; position++) {
7715
- const parameter = this.params[position];
7716
- if (!(parameter instanceof Identifier)) {
7717
- continue;
7718
- }
7719
- const parameterVariable = parameter.variable;
7720
- const argument = _arguments[position + 1] ?? UNDEFINED_EXPRESSION;
7721
- parameterVariable.updateKnownValue(argument);
7722
- }
8071
+ get hasCachedEffects() {
8072
+ return isFlagSet(this.flags, 67108864 /* Flag.hasEffects */);
7723
8073
  }
7724
- deoptimizeParameterVariableValues() {
7725
- for (const parameter of this.params) {
7726
- if (parameter instanceof Identifier) {
7727
- const parameterVariable = parameter.variable;
7728
- parameterVariable.markReassigned();
7729
- }
7730
- }
8074
+ set hasCachedEffects(value) {
8075
+ this.flags = setFlag(this.flags, 67108864 /* Flag.hasEffects */, value);
7731
8076
  }
7732
8077
  deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
7733
- if (interaction.type === INTERACTION_CALLED) {
7734
- const { parameters } = this.scope;
7735
- const { args } = interaction;
7736
- let hasRest = false;
7737
- for (let position = 0; position < args.length - 1; position++) {
7738
- const parameter = this.params[position];
7739
- // Only the "this" argument arg[0] can be null
7740
- const argument = args[position + 1];
7741
- if (argument instanceof SpreadElement) {
7742
- this.deoptimizeParameterVariableValues();
7743
- }
7744
- if (hasRest || parameter instanceof RestElement) {
7745
- hasRest = true;
7746
- argument.deoptimizePath(UNKNOWN_PATH);
7747
- }
7748
- else if (parameter instanceof Identifier) {
7749
- parameters[position][0].addEntityToBeDeoptimized(argument);
7750
- this.addArgumentToBeDeoptimized(argument);
7751
- }
7752
- else if (parameter) {
7753
- argument.deoptimizePath(UNKNOWN_PATH);
7754
- }
7755
- else {
7756
- this.addArgumentToBeDeoptimized(argument);
7757
- }
7758
- }
7759
- this.updateParameterVariableValues(args);
8078
+ if (interaction.type === INTERACTION_CALLED && path.length === 0) {
8079
+ this.scope.deoptimizeArgumentsOnCall(interaction);
7760
8080
  }
7761
8081
  else {
7762
8082
  this.getObjectEntity().deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
@@ -7768,12 +8088,7 @@ class FunctionBase extends NodeBase {
7768
8088
  // A reassignment of UNKNOWN_PATH is considered equivalent to having lost track
7769
8089
  // which means the return expression and parameters need to be reassigned
7770
8090
  this.scope.getReturnExpression().deoptimizePath(UNKNOWN_PATH);
7771
- for (const parameterList of this.scope.parameters) {
7772
- for (const parameter of parameterList) {
7773
- parameter.deoptimizePath(UNKNOWN_PATH);
7774
- parameter.markReassigned();
7775
- }
7776
- }
8091
+ this.scope.deoptimizeAllParameters();
7777
8092
  }
7778
8093
  }
7779
8094
  getLiteralValueAtPath(path, recursionTracker, origin) {
@@ -7797,8 +8112,8 @@ class FunctionBase extends NodeBase {
7797
8112
  if (path.length > 0 || interaction.type !== INTERACTION_CALLED) {
7798
8113
  return this.getObjectEntity().hasEffectsOnInteractionAtPath(path, interaction, context);
7799
8114
  }
7800
- if (this.annotationNoSideEffects) {
7801
- return false;
8115
+ if (this.hasCachedEffects) {
8116
+ return true;
7802
8117
  }
7803
8118
  if (this.async) {
7804
8119
  const { propertyReadSideEffects } = this.scope.context.options
@@ -7808,12 +8123,20 @@ class FunctionBase extends NodeBase {
7808
8123
  (propertyReadSideEffects &&
7809
8124
  (propertyReadSideEffects === 'always' ||
7810
8125
  returnExpression.hasEffectsOnInteractionAtPath(['then'], NODE_INTERACTION_UNKNOWN_ACCESS, context)))) {
8126
+ this.hasCachedEffects = true;
7811
8127
  return true;
7812
8128
  }
7813
8129
  }
7814
- for (const parameter of this.params) {
7815
- if (parameter.hasEffects(context))
8130
+ const { propertyReadSideEffects } = this.scope.context.options
8131
+ .treeshake;
8132
+ for (let index = 0; index < this.params.length; index++) {
8133
+ const parameter = this.params[index];
8134
+ if (parameter.hasEffects(context) ||
8135
+ (propertyReadSideEffects &&
8136
+ parameter.hasEffectsWhenDestructuring(context, EMPTY_PATH, interaction.args[index + 1] || UNDEFINED_EXPRESSION))) {
8137
+ this.hasCachedEffects = true;
7816
8138
  return true;
8139
+ }
7817
8140
  }
7818
8141
  return false;
7819
8142
  }
@@ -7831,21 +8154,17 @@ class FunctionBase extends NodeBase {
7831
8154
  return variable?.getOnlyFunctionCallUsed() ?? false;
7832
8155
  }
7833
8156
  include(context, includeChildrenRecursively) {
7834
- if (!this.parameterVariableValuesDeoptimized && !this.onlyFunctionCallUsed()) {
8157
+ if (!this.included)
8158
+ this.includeNode(context);
8159
+ if (!(this.parameterVariableValuesDeoptimized || this.onlyFunctionCallUsed())) {
7835
8160
  this.parameterVariableValuesDeoptimized = true;
7836
- this.deoptimizeParameterVariableValues();
8161
+ this.scope.reassignAllParameters();
7837
8162
  }
7838
- if (!this.deoptimized)
7839
- this.applyDeoptimizations();
7840
- this.included = true;
7841
8163
  const { brokenFlow } = context;
7842
8164
  context.brokenFlow = false;
7843
8165
  this.body.include(context, includeChildrenRecursively);
7844
8166
  context.brokenFlow = brokenFlow;
7845
8167
  }
7846
- includeCallArguments(context, parameters) {
7847
- this.scope.includeCallArguments(context, parameters);
7848
- }
7849
8168
  initialise() {
7850
8169
  super.initialise();
7851
8170
  if (this.body instanceof BlockStatement) {
@@ -7867,14 +8186,14 @@ class FunctionBase extends NodeBase {
7867
8186
  // so that the scope already knows all parameters and can detect conflicts
7868
8187
  // when parsing the body.
7869
8188
  const parameters = (this.params = params.map((parameter) => new (context.getNodeConstructor(parameter.type))(this, scope).parseNode(parameter)));
7870
- scope.addParameterVariables(parameters.map(parameter => parameter.declare('parameter', UNKNOWN_EXPRESSION)), parameters[parameters.length - 1] instanceof RestElement);
8189
+ scope.addParameterVariables(parameters.map(parameter => parameter.declare('parameter', EMPTY_PATH, UNKNOWN_EXPRESSION)), parameters[parameters.length - 1] instanceof RestElement);
7871
8190
  this.body = new (context.getNodeConstructor(body.type))(this, bodyScope).parseNode(body);
7872
8191
  return super.parseNode(esTreeNode);
7873
8192
  }
7874
- addArgumentToBeDeoptimized(_argument) { }
7875
- applyDeoptimizations() { }
7876
8193
  }
7877
8194
  FunctionBase.prototype.preventChildBlockScope = true;
8195
+ FunctionBase.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
8196
+ FunctionBase.prototype.applyDeoptimizations = doNotDeoptimize;
7878
8197
 
7879
8198
  class FunctionNode extends FunctionBase {
7880
8199
  constructor() {
@@ -7886,30 +8205,31 @@ class FunctionNode extends FunctionBase {
7886
8205
  this.constructedEntity = new ObjectEntity(Object.create(null), OBJECT_PROTOTYPE);
7887
8206
  // This makes sure that all deoptimizations of "this" are applied to the
7888
8207
  // constructed entity.
7889
- this.scope.thisVariable.addEntityToBeDeoptimized(this.constructedEntity);
8208
+ this.scope.thisVariable.addArgumentValue(this.constructedEntity);
7890
8209
  }
7891
8210
  deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
7892
8211
  super.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
7893
8212
  if (interaction.type === INTERACTION_CALLED && path.length === 0 && interaction.args[0]) {
7894
8213
  // args[0] is the "this" argument
7895
- this.scope.thisVariable.addEntityToBeDeoptimized(interaction.args[0]);
8214
+ this.scope.thisVariable.addArgumentValue(interaction.args[0]);
7896
8215
  }
7897
8216
  }
7898
8217
  hasEffects(context) {
7899
- if (!this.deoptimized)
7900
- this.applyDeoptimizations();
7901
8218
  if (this.annotationNoSideEffects) {
7902
8219
  return false;
7903
8220
  }
7904
8221
  return !!this.id?.hasEffects(context);
7905
8222
  }
7906
8223
  hasEffectsOnInteractionAtPath(path, interaction, context) {
7907
- if (super.hasEffectsOnInteractionAtPath(path, interaction, context))
7908
- return true;
7909
- if (this.annotationNoSideEffects) {
8224
+ if (this.annotationNoSideEffects &&
8225
+ path.length === 0 &&
8226
+ interaction.type === INTERACTION_CALLED) {
7910
8227
  return false;
7911
8228
  }
7912
- if (interaction.type === INTERACTION_CALLED) {
8229
+ if (super.hasEffectsOnInteractionAtPath(path, interaction, context)) {
8230
+ return true;
8231
+ }
8232
+ if (path.length === 0 && interaction.type === INTERACTION_CALLED) {
7913
8233
  const thisInit = context.replacedVariableInits.get(this.scope.thisVariable);
7914
8234
  context.replacedVariableInits.set(this.scope.thisVariable, interaction.withNew ? this.constructedEntity : UNKNOWN_EXPRESSION);
7915
8235
  const { brokenFlow, ignore, replacedVariableInits } = context;
@@ -7920,8 +8240,10 @@ class FunctionNode extends FunctionBase {
7920
8240
  returnYield: true,
7921
8241
  this: interaction.withNew
7922
8242
  };
7923
- if (this.body.hasEffects(context))
8243
+ if (this.body.hasEffects(context)) {
8244
+ this.hasCachedEffects = true;
7924
8245
  return true;
8246
+ }
7925
8247
  context.brokenFlow = brokenFlow;
7926
8248
  if (thisInit) {
7927
8249
  replacedVariableInits.set(this.scope.thisVariable, thisInit);
@@ -7935,7 +8257,7 @@ class FunctionNode extends FunctionBase {
7935
8257
  }
7936
8258
  include(context, includeChildrenRecursively) {
7937
8259
  super.include(context, includeChildrenRecursively);
7938
- this.id?.include();
8260
+ this.id?.include(context);
7939
8261
  const hasArguments = this.scope.argumentsVariable.included;
7940
8262
  for (const parameter of this.params) {
7941
8263
  if (!(parameter instanceof Identifier) || hasArguments) {
@@ -7943,12 +8265,18 @@ class FunctionNode extends FunctionBase {
7943
8265
  }
7944
8266
  }
7945
8267
  }
8268
+ includeNode(context) {
8269
+ this.included = true;
8270
+ const hasArguments = this.scope.argumentsVariable.included;
8271
+ for (const parameter of this.params) {
8272
+ if (!(parameter instanceof Identifier) || hasArguments) {
8273
+ parameter.includePath(UNKNOWN_PATH, context);
8274
+ }
8275
+ }
8276
+ }
7946
8277
  initialise() {
7947
8278
  super.initialise();
7948
- this.id?.declare('function', this);
7949
- }
7950
- addArgumentToBeDeoptimized(argument) {
7951
- this.scope.argumentsVariable.addArgumentToBeDeoptimized(argument);
8279
+ this.id?.declare('function', EMPTY_PATH, this);
7952
8280
  }
7953
8281
  getObjectEntity() {
7954
8282
  if (this.objectEntity !== null) {
@@ -7998,11 +8326,16 @@ function getFunctionIdInsertPosition(code, start) {
7998
8326
  }
7999
8327
  class ExportDefaultDeclaration extends NodeBase {
8000
8328
  include(context, includeChildrenRecursively) {
8001
- super.include(context, includeChildrenRecursively);
8329
+ this.included = true;
8330
+ this.declaration.include(context, includeChildrenRecursively);
8002
8331
  if (includeChildrenRecursively) {
8003
- this.scope.context.includeVariableInModule(this.variable);
8332
+ this.scope.context.includeVariableInModule(this.variable, UNKNOWN_PATH, context);
8004
8333
  }
8005
8334
  }
8335
+ includePath(path, context) {
8336
+ this.included = true;
8337
+ this.declaration.includePath(path, context);
8338
+ }
8006
8339
  initialise() {
8007
8340
  super.initialise();
8008
8341
  const declaration = this.declaration;
@@ -8047,7 +8380,6 @@ class ExportDefaultDeclaration extends NodeBase {
8047
8380
  }
8048
8381
  this.declaration.render(code, options);
8049
8382
  }
8050
- applyDeoptimizations() { }
8051
8383
  renderNamedDeclaration(code, declarationStart, idInsertPosition, options) {
8052
8384
  const { exportNamesByVariable, format, snippets: { getPropertyAccess } } = options;
8053
8385
  const name = this.variable.getName(getPropertyAccess);
@@ -8078,6 +8410,8 @@ class ExportDefaultDeclaration extends NodeBase {
8078
8410
  }
8079
8411
  }
8080
8412
  ExportDefaultDeclaration.prototype.needsBoundaries = true;
8413
+ ExportDefaultDeclaration.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
8414
+ ExportDefaultDeclaration.prototype.applyDeoptimizations = doNotDeoptimize;
8081
8415
 
8082
8416
  const needsEscapeRegEx = /[\n\r'\\\u2028\u2029]/;
8083
8417
  const quoteNewlineRegEx = /([\n\r'\u2028\u2029])/g;
@@ -8347,6 +8681,7 @@ class Literal extends NodeBase {
8347
8681
  }
8348
8682
  }
8349
8683
  }
8684
+ Literal.prototype.includeNode = onlyIncludeSelf;
8350
8685
 
8351
8686
  function getChainElementLiteralValueAtPath(element, object, path, recursionTracker, origin) {
8352
8687
  if ('getLiteralValueAtPathAsChainElement' in object) {
@@ -8362,8 +8697,6 @@ function getChainElementLiteralValueAtPath(element, object, path, recursionTrack
8362
8697
  return element.getLiteralValueAtPath(path, recursionTracker, origin);
8363
8698
  }
8364
8699
 
8365
- // To avoid infinite recursions
8366
- const MAX_PATH_DEPTH = 7;
8367
8700
  function getResolvablePropertyKey(memberExpression) {
8368
8701
  return memberExpression.computed
8369
8702
  ? getResolvableComputedPropertyKey(memberExpression.property)
@@ -8462,18 +8795,27 @@ class MemberExpression extends NodeBase {
8462
8795
  }
8463
8796
  else if (!this.isUndefined) {
8464
8797
  if (path.length < MAX_PATH_DEPTH) {
8465
- this.object.deoptimizeArgumentsOnInteractionAtPath(interaction, [this.getPropertyKey(), ...path], recursionTracker);
8798
+ this.object.deoptimizeArgumentsOnInteractionAtPath(interaction, this.propertyKey === UnknownKey ? UNKNOWN_PATH : [this.propertyKey, ...path], recursionTracker);
8466
8799
  }
8467
8800
  else {
8468
8801
  deoptimizeInteraction(interaction);
8469
8802
  }
8470
8803
  }
8471
8804
  }
8805
+ deoptimizeAssignment(destructuredInitPath, init) {
8806
+ this.deoptimizePath(EMPTY_PATH);
8807
+ init.deoptimizePath([...destructuredInitPath, UnknownKey]);
8808
+ }
8472
8809
  deoptimizeCache() {
8810
+ if (this.propertyKey === this.dynamicPropertyKey)
8811
+ return;
8473
8812
  const { expressionsToBeDeoptimized, object } = this;
8474
8813
  this.expressionsToBeDeoptimized = parseAst_js.EMPTY_ARRAY;
8475
- this.propertyKey = UnknownKey;
8814
+ this.dynamicPropertyKey = this.propertyKey;
8476
8815
  object.deoptimizePath(UNKNOWN_PATH);
8816
+ if (this.included) {
8817
+ object.includePath(UNKNOWN_PATH, createInclusionContext());
8818
+ }
8477
8819
  for (const expression of expressionsToBeDeoptimized) {
8478
8820
  expression.deoptimizeCache();
8479
8821
  }
@@ -8484,11 +8826,13 @@ class MemberExpression extends NodeBase {
8484
8826
  if (this.variable) {
8485
8827
  this.variable.deoptimizePath(path);
8486
8828
  }
8487
- else if (!this.isUndefined && path.length < MAX_PATH_DEPTH) {
8488
- const propertyKey = this.getPropertyKey();
8829
+ else if (!this.isUndefined) {
8830
+ const { propertyKey } = this;
8489
8831
  this.object.deoptimizePath([
8490
8832
  propertyKey === UnknownKey ? UnknownNonAccessorKey : propertyKey,
8491
- ...path
8833
+ ...(path.length < MAX_PATH_DEPTH
8834
+ ? path
8835
+ : [...path.slice(0, MAX_PATH_DEPTH), UnknownKey])
8492
8836
  ]);
8493
8837
  }
8494
8838
  }
@@ -8499,9 +8843,11 @@ class MemberExpression extends NodeBase {
8499
8843
  if (this.isUndefined) {
8500
8844
  return undefined;
8501
8845
  }
8502
- if (this.propertyKey !== UnknownKey && path.length < MAX_PATH_DEPTH) {
8503
- this.expressionsToBeDeoptimized.push(origin);
8504
- return this.object.getLiteralValueAtPath([this.getPropertyKey(), ...path], recursionTracker, origin);
8846
+ const propertyKey = this.getDynamicPropertyKey();
8847
+ if (propertyKey !== UnknownKey && path.length < MAX_PATH_DEPTH) {
8848
+ if (propertyKey !== this.propertyKey)
8849
+ this.expressionsToBeDeoptimized.push(origin);
8850
+ return this.object.getLiteralValueAtPath([propertyKey, ...path], recursionTracker, origin);
8505
8851
  }
8506
8852
  return UnknownValue;
8507
8853
  }
@@ -8521,9 +8867,11 @@ class MemberExpression extends NodeBase {
8521
8867
  if (this.isUndefined) {
8522
8868
  return [UNDEFINED_EXPRESSION, false];
8523
8869
  }
8524
- if (this.propertyKey !== UnknownKey && path.length < MAX_PATH_DEPTH) {
8525
- this.expressionsToBeDeoptimized.push(origin);
8526
- return this.object.getReturnExpressionWhenCalledAtPath([this.getPropertyKey(), ...path], interaction, recursionTracker, origin);
8870
+ const propertyKey = this.getDynamicPropertyKey();
8871
+ if (propertyKey !== UnknownKey && path.length < MAX_PATH_DEPTH) {
8872
+ if (propertyKey !== this.propertyKey)
8873
+ this.expressionsToBeDeoptimized.push(origin);
8874
+ return this.object.getReturnExpressionWhenCalledAtPath([propertyKey, ...path], interaction, recursionTracker, origin);
8527
8875
  }
8528
8876
  return UNKNOWN_RETURN_EXPRESSION;
8529
8877
  }
@@ -8569,14 +8917,45 @@ class MemberExpression extends NodeBase {
8569
8917
  return true;
8570
8918
  }
8571
8919
  if (path.length < MAX_PATH_DEPTH) {
8572
- return this.object.hasEffectsOnInteractionAtPath([this.getPropertyKey(), ...path], interaction, context);
8920
+ return this.object.hasEffectsOnInteractionAtPath([this.getDynamicPropertyKey(), ...path], interaction, context);
8573
8921
  }
8574
8922
  return true;
8575
8923
  }
8924
+ hasEffectsWhenDestructuring(context, destructuredInitPath, init) {
8925
+ return (destructuredInitPath.length > 0 &&
8926
+ init.hasEffectsOnInteractionAtPath(destructuredInitPath, NODE_INTERACTION_UNKNOWN_ACCESS, context));
8927
+ }
8576
8928
  include(context, includeChildrenRecursively) {
8929
+ if (!this.included)
8930
+ this.includeNode(context);
8931
+ this.object.include(context, includeChildrenRecursively);
8932
+ this.property.include(context, includeChildrenRecursively);
8933
+ }
8934
+ includeNode(context) {
8935
+ this.included = true;
8577
8936
  if (!this.deoptimized)
8578
8937
  this.applyDeoptimizations();
8579
- this.includeProperties(context, includeChildrenRecursively);
8938
+ if (this.variable) {
8939
+ this.scope.context.includeVariableInModule(this.variable, EMPTY_PATH, context);
8940
+ }
8941
+ else if (!this.isUndefined) {
8942
+ this.object.includePath([this.propertyKey], context);
8943
+ }
8944
+ }
8945
+ includePath(path, context) {
8946
+ if (!this.included)
8947
+ this.includeNode(context);
8948
+ if (this.variable) {
8949
+ this.variable?.includePath(path, context);
8950
+ }
8951
+ else if (!this.isUndefined) {
8952
+ this.object.includePath([
8953
+ this.propertyKey,
8954
+ ...(path.length < MAX_PATH_DEPTH
8955
+ ? path
8956
+ : [...path.slice(0, MAX_PATH_DEPTH), UnknownKey])
8957
+ ], context);
8958
+ }
8580
8959
  }
8581
8960
  includeAsAssignmentTarget(context, includeChildrenRecursively, deoptimizeAccess) {
8582
8961
  if (!this.assignmentDeoptimized)
@@ -8585,20 +8964,34 @@ class MemberExpression extends NodeBase {
8585
8964
  this.include(context, includeChildrenRecursively);
8586
8965
  }
8587
8966
  else {
8588
- this.includeProperties(context, includeChildrenRecursively);
8967
+ if (!this.included)
8968
+ this.includeNode(context);
8969
+ this.object.include(context, includeChildrenRecursively);
8970
+ this.property.include(context, includeChildrenRecursively);
8589
8971
  }
8590
8972
  }
8591
- includeCallArguments(context, parameters) {
8973
+ includeCallArguments(context, interaction) {
8592
8974
  if (this.variable) {
8593
- this.variable.includeCallArguments(context, parameters);
8975
+ this.variable.includeCallArguments(context, interaction);
8594
8976
  }
8595
8977
  else {
8596
- super.includeCallArguments(context, parameters);
8978
+ super.includeCallArguments(context, interaction);
8979
+ }
8980
+ }
8981
+ includeDestructuredIfNecessary(context, destructuredInitPath, init) {
8982
+ if ((this.included ||=
8983
+ destructuredInitPath.length > 0 &&
8984
+ !context.brokenFlow &&
8985
+ init.hasEffectsOnInteractionAtPath(destructuredInitPath, NODE_INTERACTION_UNKNOWN_ACCESS, createHasEffectsContext()))) {
8986
+ init.include(context, false);
8987
+ return true;
8597
8988
  }
8989
+ return false;
8598
8990
  }
8599
8991
  initialise() {
8600
8992
  super.initialise();
8601
- this.propertyKey = getResolvablePropertyKey(this);
8993
+ this.dynamicPropertyKey = getResolvablePropertyKey(this);
8994
+ this.propertyKey = this.dynamicPropertyKey === null ? UnknownKey : this.dynamicPropertyKey;
8602
8995
  this.accessInteraction = { args: [this.object], type: INTERACTION_ACCESSED };
8603
8996
  }
8604
8997
  render(code, options, { renderedParentType, isCalleeOfRenderedParent, renderedSurroundingElement } = parseAst_js.BLANK) {
@@ -8635,8 +9028,7 @@ class MemberExpression extends NodeBase {
8635
9028
  this.bound &&
8636
9029
  propertyReadSideEffects &&
8637
9030
  !(this.variable || this.isUndefined)) {
8638
- const propertyKey = this.getPropertyKey();
8639
- this.object.deoptimizeArgumentsOnInteractionAtPath(this.accessInteraction, [propertyKey], SHARED_RECURSION_TRACKER);
9031
+ this.object.deoptimizeArgumentsOnInteractionAtPath(this.accessInteraction, [this.propertyKey], SHARED_RECURSION_TRACKER);
8640
9032
  this.scope.context.requestTreeshakingPass();
8641
9033
  }
8642
9034
  if (this.variable) {
@@ -8653,7 +9045,7 @@ class MemberExpression extends NodeBase {
8653
9045
  this.bound &&
8654
9046
  propertyReadSideEffects &&
8655
9047
  !(this.variable || this.isUndefined)) {
8656
- this.object.deoptimizeArgumentsOnInteractionAtPath(this.assignmentInteraction, [this.getPropertyKey()], SHARED_RECURSION_TRACKER);
9048
+ this.object.deoptimizeArgumentsOnInteractionAtPath(this.assignmentInteraction, [this.propertyKey], SHARED_RECURSION_TRACKER);
8657
9049
  this.scope.context.requestTreeshakingPass();
8658
9050
  }
8659
9051
  }
@@ -8662,24 +9054,24 @@ class MemberExpression extends NodeBase {
8662
9054
  const variable = this.scope.findVariable(this.object.name);
8663
9055
  if (variable.isNamespace) {
8664
9056
  if (this.variable) {
8665
- this.scope.context.includeVariableInModule(this.variable);
9057
+ this.scope.context.includeVariableInModule(this.variable, UNKNOWN_PATH, createInclusionContext());
8666
9058
  }
8667
9059
  this.scope.context.log(parseAst_js.LOGLEVEL_WARN, parseAst_js.logIllegalImportReassignment(this.object.name, this.scope.context.module.id), this.start);
8668
9060
  }
8669
9061
  }
8670
9062
  }
8671
- getPropertyKey() {
8672
- if (this.propertyKey === null) {
8673
- this.propertyKey = UnknownKey;
9063
+ getDynamicPropertyKey() {
9064
+ if (this.dynamicPropertyKey === null) {
9065
+ this.dynamicPropertyKey = this.propertyKey;
8674
9066
  const value = this.property.getLiteralValueAtPath(EMPTY_PATH, SHARED_RECURSION_TRACKER, this);
8675
- return (this.propertyKey =
9067
+ return (this.dynamicPropertyKey =
8676
9068
  value === SymbolToStringTag
8677
9069
  ? value
8678
9070
  : typeof value === 'symbol'
8679
9071
  ? UnknownKey
8680
9072
  : String(value));
8681
9073
  }
8682
- return this.propertyKey;
9074
+ return this.dynamicPropertyKey;
8683
9075
  }
8684
9076
  hasAccessEffect(context) {
8685
9077
  const { propertyReadSideEffects } = this.scope.context.options
@@ -8687,17 +9079,7 @@ class MemberExpression extends NodeBase {
8687
9079
  return (!(this.variable || this.isUndefined) &&
8688
9080
  propertyReadSideEffects &&
8689
9081
  (propertyReadSideEffects === 'always' ||
8690
- this.object.hasEffectsOnInteractionAtPath([this.getPropertyKey()], this.accessInteraction, context)));
8691
- }
8692
- includeProperties(context, includeChildrenRecursively) {
8693
- if (!this.included) {
8694
- this.included = true;
8695
- if (this.variable) {
8696
- this.scope.context.includeVariableInModule(this.variable);
8697
- }
8698
- }
8699
- this.object.include(context, includeChildrenRecursively);
8700
- this.property.include(context, includeChildrenRecursively);
9082
+ this.object.hasEffectsOnInteractionAtPath([this.getDynamicPropertyKey()], this.accessInteraction, context)));
8701
9083
  }
8702
9084
  }
8703
9085
  function resolveNamespaceVariables(baseVariable, path, astContext) {
@@ -8741,18 +9123,20 @@ class MetaProperty extends NodeBase {
8741
9123
  return path.length > 1 || type !== INTERACTION_ACCESSED;
8742
9124
  }
8743
9125
  include() {
8744
- if (!this.included) {
8745
- this.included = true;
8746
- if (this.meta.name === IMPORT) {
8747
- this.scope.context.addImportMeta(this);
8748
- const parent = this.parent;
8749
- const metaProperty = (this.metaProperty =
8750
- parent instanceof MemberExpression && typeof parent.propertyKey === 'string'
8751
- ? parent.propertyKey
8752
- : null);
8753
- if (metaProperty?.startsWith(FILE_PREFIX)) {
8754
- this.referenceId = metaProperty.slice(FILE_PREFIX.length);
8755
- }
9126
+ if (!this.included)
9127
+ this.includeNode();
9128
+ }
9129
+ includeNode() {
9130
+ this.included = true;
9131
+ if (this.meta.name === IMPORT) {
9132
+ this.scope.context.addImportMeta(this);
9133
+ const parent = this.parent;
9134
+ const metaProperty = (this.metaProperty =
9135
+ parent instanceof MemberExpression && typeof parent.propertyKey === 'string'
9136
+ ? parent.propertyKey
9137
+ : null);
9138
+ if (metaProperty?.startsWith(FILE_PREFIX)) {
9139
+ this.referenceId = metaProperty.slice(FILE_PREFIX.length);
8756
9140
  }
8757
9141
  }
8758
9142
  }
@@ -8859,7 +9243,7 @@ class UndefinedVariable extends Variable {
8859
9243
 
8860
9244
  class ExportDefaultVariable extends LocalVariable {
8861
9245
  constructor(name, exportDefaultDeclaration, context) {
8862
- super(name, exportDefaultDeclaration, exportDefaultDeclaration.declaration, context, 'other');
9246
+ super(name, exportDefaultDeclaration, exportDefaultDeclaration.declaration, EMPTY_PATH, context, 'other');
8863
9247
  this.hasId = false;
8864
9248
  this.originalId = null;
8865
9249
  this.originalVariable = null;
@@ -9008,8 +9392,8 @@ class NamespaceVariable extends Variable {
9008
9392
  return (!memberVariable ||
9009
9393
  memberVariable.hasEffectsOnInteractionAtPath(path.slice(1), interaction, context));
9010
9394
  }
9011
- include() {
9012
- super.include();
9395
+ includePath(path, context) {
9396
+ super.includePath(path, context);
9013
9397
  this.context.includeAllExports();
9014
9398
  }
9015
9399
  prepare(accessedGlobalsByScope) {
@@ -9102,9 +9486,9 @@ class SyntheticNamedExportVariable extends Variable {
9102
9486
  getName(getPropertyAccess) {
9103
9487
  return `${this.syntheticNamespace.getName(getPropertyAccess)}${getPropertyAccess(this.name)}`;
9104
9488
  }
9105
- include() {
9106
- super.include();
9107
- this.context.includeVariableInModule(this.syntheticNamespace);
9489
+ includePath(path, context) {
9490
+ super.includePath(path, context);
9491
+ this.context.includeVariableInModule(this.syntheticNamespace, path, context);
9108
9492
  }
9109
9493
  setRenderNames(baseName, name) {
9110
9494
  super.setRenderNames(baseName, name);
@@ -12280,21 +12664,37 @@ class ArrayPattern extends NodeBase {
12280
12664
  element?.addExportedVariables(variables, exportNamesByVariable);
12281
12665
  }
12282
12666
  }
12283
- declare(kind) {
12667
+ declare(kind, destructuredInitPath, init) {
12284
12668
  const variables = [];
12669
+ const includedPatternPath = getIncludedPatternPath(destructuredInitPath);
12285
12670
  for (const element of this.elements) {
12286
12671
  if (element !== null) {
12287
- variables.push(...element.declare(kind, UNKNOWN_EXPRESSION));
12672
+ variables.push(...element.declare(kind, includedPatternPath, init));
12288
12673
  }
12289
12674
  }
12290
12675
  return variables;
12291
12676
  }
12677
+ deoptimizeAssignment(destructuredInitPath, init) {
12678
+ const includedPatternPath = getIncludedPatternPath(destructuredInitPath);
12679
+ for (const element of this.elements) {
12680
+ element?.deoptimizeAssignment(includedPatternPath, init);
12681
+ }
12682
+ }
12292
12683
  // Patterns can only be deoptimized at the empty path at the moment
12293
12684
  deoptimizePath() {
12294
12685
  for (const element of this.elements) {
12295
12686
  element?.deoptimizePath(EMPTY_PATH);
12296
12687
  }
12297
12688
  }
12689
+ hasEffectsWhenDestructuring(context, destructuredInitPath, init) {
12690
+ const includedPatternPath = getIncludedPatternPath(destructuredInitPath);
12691
+ for (const element of this.elements) {
12692
+ if (element?.hasEffectsWhenDestructuring(context, includedPatternPath, init)) {
12693
+ return true;
12694
+ }
12695
+ }
12696
+ return false;
12697
+ }
12298
12698
  // Patterns are only checked at the empty path at the moment
12299
12699
  hasEffectsOnInteractionAtPath(_path, interaction, context) {
12300
12700
  for (const element of this.elements) {
@@ -12303,12 +12703,38 @@ class ArrayPattern extends NodeBase {
12303
12703
  }
12304
12704
  return false;
12305
12705
  }
12706
+ includeDestructuredIfNecessary(context, destructuredInitPath, init) {
12707
+ let included = false;
12708
+ const includedPatternPath = getIncludedPatternPath(destructuredInitPath);
12709
+ for (const element of this.elements) {
12710
+ if (element) {
12711
+ element.included ||= included;
12712
+ included =
12713
+ element.includeDestructuredIfNecessary(context, includedPatternPath, init) || included;
12714
+ }
12715
+ }
12716
+ if (included) {
12717
+ // This is necessary so that if any pattern element is included, all are
12718
+ // included for proper deconflicting
12719
+ for (const element of this.elements) {
12720
+ if (element && !element.included) {
12721
+ element.included = true;
12722
+ element.includeDestructuredIfNecessary(context, includedPatternPath, init);
12723
+ }
12724
+ }
12725
+ }
12726
+ return (this.included ||= included);
12727
+ }
12306
12728
  markDeclarationReached() {
12307
12729
  for (const element of this.elements) {
12308
12730
  element?.markDeclarationReached();
12309
12731
  }
12310
12732
  }
12311
12733
  }
12734
+ ArrayPattern.prototype.includeNode = onlyIncludeSelf;
12735
+ const getIncludedPatternPath = (destructuredInitPath) => destructuredInitPath.at(-1) === UnknownKey
12736
+ ? destructuredInitPath
12737
+ : [...destructuredInitPath, UnknownInteger];
12312
12738
 
12313
12739
  class ArrowFunctionExpression extends FunctionBase {
12314
12740
  constructor() {
@@ -12325,17 +12751,17 @@ class ArrowFunctionExpression extends FunctionBase {
12325
12751
  this.scope = new ReturnValueScope(parentScope, false);
12326
12752
  }
12327
12753
  hasEffects() {
12328
- if (!this.deoptimized)
12329
- this.applyDeoptimizations();
12330
12754
  return false;
12331
12755
  }
12332
12756
  hasEffectsOnInteractionAtPath(path, interaction, context) {
12757
+ if (this.annotationNoSideEffects &&
12758
+ path.length === 0 &&
12759
+ interaction.type === INTERACTION_CALLED) {
12760
+ return false;
12761
+ }
12333
12762
  if (super.hasEffectsOnInteractionAtPath(path, interaction, context)) {
12334
12763
  return true;
12335
12764
  }
12336
- if (this.annotationNoSideEffects) {
12337
- return false;
12338
- }
12339
12765
  if (interaction.type === INTERACTION_CALLED) {
12340
12766
  const { ignore, brokenFlow } = context;
12341
12767
  context.ignore = {
@@ -12365,6 +12791,15 @@ class ArrowFunctionExpression extends FunctionBase {
12365
12791
  }
12366
12792
  }
12367
12793
  }
12794
+ includeNode(context) {
12795
+ this.included = true;
12796
+ this.body.includePath(UNKNOWN_PATH, context);
12797
+ for (const parameter of this.params) {
12798
+ if (!(parameter instanceof Identifier)) {
12799
+ parameter.includePath(UNKNOWN_PATH, context);
12800
+ }
12801
+ }
12802
+ }
12368
12803
  getObjectEntity() {
12369
12804
  if (this.objectEntity !== null) {
12370
12805
  return this.objectEntity;
@@ -12384,13 +12819,18 @@ class ObjectPattern extends NodeBase {
12384
12819
  }
12385
12820
  }
12386
12821
  }
12387
- declare(kind, init) {
12822
+ declare(kind, destructuredInitPath, init) {
12388
12823
  const variables = [];
12389
12824
  for (const property of this.properties) {
12390
- variables.push(...property.declare(kind, init));
12825
+ variables.push(...property.declare(kind, destructuredInitPath, init));
12391
12826
  }
12392
12827
  return variables;
12393
12828
  }
12829
+ deoptimizeAssignment(destructuredInitPath, init) {
12830
+ for (const property of this.properties) {
12831
+ property.deoptimizeAssignment(destructuredInitPath, init);
12832
+ }
12833
+ }
12394
12834
  deoptimizePath(path) {
12395
12835
  if (path.length === 0) {
12396
12836
  for (const property of this.properties) {
@@ -12408,12 +12848,46 @@ class ObjectPattern extends NodeBase {
12408
12848
  }
12409
12849
  return false;
12410
12850
  }
12851
+ hasEffectsWhenDestructuring(context, destructuredInitPath, init) {
12852
+ for (const property of this.properties) {
12853
+ if (property.hasEffectsWhenDestructuring(context, destructuredInitPath, init))
12854
+ return true;
12855
+ }
12856
+ return false;
12857
+ }
12858
+ includeDestructuredIfNecessary(context, destructuredInitPath, init) {
12859
+ let included = false;
12860
+ for (const property of this.properties) {
12861
+ included =
12862
+ property.includeDestructuredIfNecessary(context, destructuredInitPath, init) || included;
12863
+ }
12864
+ return (this.included ||= included);
12865
+ }
12411
12866
  markDeclarationReached() {
12412
12867
  for (const property of this.properties) {
12413
12868
  property.markDeclarationReached();
12414
12869
  }
12415
12870
  }
12871
+ render(code, options) {
12872
+ if (this.properties.length > 0) {
12873
+ const separatedNodes = getCommaSeparatedNodesWithBoundaries(this.properties, code, this.start + 1, this.end - 1);
12874
+ let lastSeparatorPos = null;
12875
+ for (const { node, separator, start, end } of separatedNodes) {
12876
+ if (!node.included) {
12877
+ treeshakeNode(node, code, start, end);
12878
+ continue;
12879
+ }
12880
+ lastSeparatorPos = separator;
12881
+ node.render(code, options);
12882
+ }
12883
+ if (lastSeparatorPos) {
12884
+ code.remove(lastSeparatorPos, this.end - 1);
12885
+ }
12886
+ }
12887
+ }
12416
12888
  }
12889
+ ObjectPattern.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
12890
+ ObjectPattern.prototype.applyDeoptimizations = doNotDeoptimize;
12417
12891
 
12418
12892
  class AssignmentExpression extends NodeBase {
12419
12893
  hasEffects(context) {
@@ -12422,7 +12896,9 @@ class AssignmentExpression extends NodeBase {
12422
12896
  this.applyDeoptimizations();
12423
12897
  // MemberExpressions do not access the property before assignments if the
12424
12898
  // operator is '='.
12425
- return (right.hasEffects(context) || left.hasEffectsAsAssignmentTarget(context, operator !== '='));
12899
+ return (right.hasEffects(context) ||
12900
+ left.hasEffectsAsAssignmentTarget(context, operator !== '=') ||
12901
+ this.left.hasEffectsWhenDestructuring?.(context, EMPTY_PATH, right));
12426
12902
  }
12427
12903
  hasEffectsOnInteractionAtPath(path, interaction, context) {
12428
12904
  return this.right.hasEffectsOnInteractionAtPath(path, interaction, context);
@@ -12431,15 +12907,24 @@ class AssignmentExpression extends NodeBase {
12431
12907
  const { deoptimized, left, right, operator } = this;
12432
12908
  if (!deoptimized)
12433
12909
  this.applyDeoptimizations();
12434
- this.included = true;
12910
+ if (!this.included)
12911
+ this.includeNode(context);
12912
+ const hasEffectsContext = createHasEffectsContext();
12435
12913
  if (includeChildrenRecursively ||
12436
12914
  operator !== '=' ||
12437
12915
  left.included ||
12438
- left.hasEffectsAsAssignmentTarget(createHasEffectsContext(), false)) {
12916
+ left.hasEffectsAsAssignmentTarget(hasEffectsContext, false) ||
12917
+ left.hasEffectsWhenDestructuring?.(hasEffectsContext, EMPTY_PATH, right)) {
12439
12918
  left.includeAsAssignmentTarget(context, includeChildrenRecursively, operator !== '=');
12440
12919
  }
12441
12920
  right.include(context, includeChildrenRecursively);
12442
12921
  }
12922
+ includeNode(context) {
12923
+ this.included = true;
12924
+ if (!this.deoptimized)
12925
+ this.applyDeoptimizations();
12926
+ this.right.includePath(UNKNOWN_PATH, context);
12927
+ }
12443
12928
  initialise() {
12444
12929
  super.initialise();
12445
12930
  if (this.left instanceof Identifier) {
@@ -12500,8 +12985,7 @@ class AssignmentExpression extends NodeBase {
12500
12985
  }
12501
12986
  applyDeoptimizations() {
12502
12987
  this.deoptimized = true;
12503
- this.left.deoptimizePath(EMPTY_PATH);
12504
- this.right.deoptimizePath(UNKNOWN_PATH);
12988
+ this.left.deoptimizeAssignment(EMPTY_PATH, this.right);
12505
12989
  this.scope.context.requestTreeshakingPass();
12506
12990
  }
12507
12991
  }
@@ -12510,8 +12994,11 @@ class AssignmentPattern extends NodeBase {
12510
12994
  addExportedVariables(variables, exportNamesByVariable) {
12511
12995
  this.left.addExportedVariables(variables, exportNamesByVariable);
12512
12996
  }
12513
- declare(kind, init) {
12514
- return this.left.declare(kind, init);
12997
+ declare(kind, destructuredInitPath, init) {
12998
+ return this.left.declare(kind, destructuredInitPath, init);
12999
+ }
13000
+ deoptimizeAssignment(destructuredInitPath, init) {
13001
+ this.left.deoptimizeAssignment(destructuredInitPath, init);
12515
13002
  }
12516
13003
  deoptimizePath(path) {
12517
13004
  if (path.length === 0) {
@@ -12521,6 +13008,29 @@ class AssignmentPattern extends NodeBase {
12521
13008
  hasEffectsOnInteractionAtPath(path, interaction, context) {
12522
13009
  return (path.length > 0 || this.left.hasEffectsOnInteractionAtPath(EMPTY_PATH, interaction, context));
12523
13010
  }
13011
+ hasEffectsWhenDestructuring(context, destructuredInitPath, init) {
13012
+ return this.left.hasEffectsWhenDestructuring(context, destructuredInitPath, init);
13013
+ }
13014
+ includeDestructuredIfNecessary(context, destructuredInitPath, init) {
13015
+ let included = this.left.includeDestructuredIfNecessary(context, destructuredInitPath, init) ||
13016
+ this.included;
13017
+ if ((included ||= this.right.shouldBeIncluded(context))) {
13018
+ this.right.include(context, false);
13019
+ if (!this.left.included) {
13020
+ this.left.included = true;
13021
+ // Unfortunately, we need to include the left side again now, so that
13022
+ // any declared variables are properly included.
13023
+ this.left.includeDestructuredIfNecessary(context, destructuredInitPath, init);
13024
+ }
13025
+ }
13026
+ return (this.included = included);
13027
+ }
13028
+ includeNode(context) {
13029
+ this.included = true;
13030
+ if (!this.deoptimized)
13031
+ this.applyDeoptimizations();
13032
+ this.right.includePath(UNKNOWN_PATH, context);
13033
+ }
12524
13034
  markDeclarationReached() {
12525
13035
  this.left.markDeclarationReached();
12526
13036
  }
@@ -12543,22 +13053,34 @@ class AwaitExpression extends NodeBase {
12543
13053
  return true;
12544
13054
  }
12545
13055
  include(context, includeChildrenRecursively) {
13056
+ if (!this.included)
13057
+ this.includeNode(context);
13058
+ this.argument.include(context, includeChildrenRecursively);
13059
+ }
13060
+ includeNode(context) {
13061
+ this.included = true;
12546
13062
  if (!this.deoptimized)
12547
13063
  this.applyDeoptimizations();
12548
- if (!this.included) {
12549
- this.included = true;
12550
- checkTopLevelAwait: if (!this.scope.context.usesTopLevelAwait) {
12551
- let parent = this.parent;
12552
- do {
12553
- if (parent instanceof FunctionNode || parent instanceof ArrowFunctionExpression)
12554
- break checkTopLevelAwait;
12555
- } while ((parent = parent.parent));
12556
- this.scope.context.usesTopLevelAwait = true;
12557
- }
13064
+ checkTopLevelAwait: if (!this.scope.context.usesTopLevelAwait) {
13065
+ let parent = this.parent;
13066
+ do {
13067
+ if (parent instanceof FunctionNode || parent instanceof ArrowFunctionExpression)
13068
+ break checkTopLevelAwait;
13069
+ } while ((parent = parent.parent));
13070
+ this.scope.context.usesTopLevelAwait = true;
12558
13071
  }
12559
- this.argument.include(context, includeChildrenRecursively);
13072
+ // Thenables need to be included
13073
+ this.argument.includePath(THEN_PATH, context);
13074
+ }
13075
+ includePath(path, context) {
13076
+ if (!this.deoptimized)
13077
+ this.applyDeoptimizations();
13078
+ if (!this.included)
13079
+ this.includeNode(context);
13080
+ this.argument.includePath(path, context);
12560
13081
  }
12561
13082
  }
13083
+ const THEN_PATH = ['then'];
12562
13084
 
12563
13085
  const binaryOperators = {
12564
13086
  '!=': (left, right) => left != right,
@@ -12614,6 +13136,12 @@ class BinaryExpression extends NodeBase {
12614
13136
  hasEffectsOnInteractionAtPath(path, { type }) {
12615
13137
  return type !== INTERACTION_ACCESSED || path.length > 1;
12616
13138
  }
13139
+ includeNode(context) {
13140
+ this.included = true;
13141
+ if (this.operator === 'in') {
13142
+ this.right.includePath(UNKNOWN_PATH, context);
13143
+ }
13144
+ }
12617
13145
  removeAnnotations(code) {
12618
13146
  this.left.removeAnnotations(code);
12619
13147
  }
@@ -12622,6 +13150,7 @@ class BinaryExpression extends NodeBase {
12622
13150
  this.right.render(code, options);
12623
13151
  }
12624
13152
  }
13153
+ BinaryExpression.prototype.applyDeoptimizations = doNotDeoptimize;
12625
13154
 
12626
13155
  class BreakStatement extends NodeBase {
12627
13156
  hasEffects(context) {
@@ -12641,7 +13170,7 @@ class BreakStatement extends NodeBase {
12641
13170
  include(context) {
12642
13171
  this.included = true;
12643
13172
  if (this.label) {
12644
- this.label.include();
13173
+ this.label.include(context);
12645
13174
  context.includedLabels.add(this.label.name);
12646
13175
  }
12647
13176
  else {
@@ -12650,6 +13179,8 @@ class BreakStatement extends NodeBase {
12650
13179
  context.brokenFlow = true;
12651
13180
  }
12652
13181
  }
13182
+ BreakStatement.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
13183
+ BreakStatement.prototype.applyDeoptimizations = doNotDeoptimize;
12653
13184
 
12654
13185
  function renderCallArguments(code, options, node) {
12655
13186
  if (node.arguments.length > 0) {
@@ -12836,10 +13367,14 @@ class CallExpression extends CallExpressionBase {
12836
13367
  this.callee.hasEffectsOnInteractionAtPath(EMPTY_PATH, this.interaction, context)));
12837
13368
  }
12838
13369
  include(context, includeChildrenRecursively) {
12839
- if (!this.deoptimized)
12840
- this.applyDeoptimizations();
13370
+ if (!this.included)
13371
+ this.includeNode(context);
12841
13372
  if (includeChildrenRecursively) {
12842
- super.include(context, includeChildrenRecursively);
13373
+ this.callee.include(context, true);
13374
+ for (const argument of this.arguments) {
13375
+ argument.includePath(UNKNOWN_PATH, context);
13376
+ argument.include(context, true);
13377
+ }
12843
13378
  if (includeChildrenRecursively === INCLUDE_PARAMETERS &&
12844
13379
  this.callee instanceof Identifier &&
12845
13380
  this.callee.variable) {
@@ -12847,10 +13382,24 @@ class CallExpression extends CallExpressionBase {
12847
13382
  }
12848
13383
  }
12849
13384
  else {
12850
- this.included = true;
12851
- this.callee.include(context, false);
13385
+ // If the callee is a member expression and does not have a variable, its
13386
+ // object will already be included via the first argument of the
13387
+ // interaction in includeCallArguments. Including it again can lead to
13388
+ // severe performance problems.
13389
+ if (this.callee instanceof MemberExpression && !this.callee.variable) {
13390
+ this.callee.property.include(context, false);
13391
+ }
13392
+ else {
13393
+ this.callee.include(context, false);
13394
+ }
13395
+ this.callee.includeCallArguments(context, this.interaction);
12852
13396
  }
12853
- this.callee.includeCallArguments(context, this.arguments);
13397
+ }
13398
+ includeNode(context) {
13399
+ this.included = true;
13400
+ if (!this.deoptimized)
13401
+ this.applyDeoptimizations();
13402
+ this.callee.includePath(UNKNOWN_PATH, context);
12854
13403
  }
12855
13404
  initialise() {
12856
13405
  super.initialise();
@@ -12889,13 +13438,14 @@ class CatchClause extends NodeBase {
12889
13438
  this.type = type;
12890
13439
  if (param) {
12891
13440
  this.param = new (this.scope.context.getNodeConstructor(param.type))(this, this.scope).parseNode(param);
12892
- this.param.declare('parameter', UNKNOWN_EXPRESSION);
13441
+ this.param.declare('parameter', EMPTY_PATH, UNKNOWN_EXPRESSION);
12893
13442
  }
12894
13443
  this.body = new BlockStatement(this, this.scope.bodyScope).parseNode(body);
12895
13444
  return super.parseNode(esTreeNode);
12896
13445
  }
12897
13446
  }
12898
13447
  CatchClause.prototype.preventChildBlockScope = true;
13448
+ CatchClause.prototype.includeNode = onlyIncludeSelf;
12899
13449
 
12900
13450
  class ChainExpression extends NodeBase {
12901
13451
  // deoptimizations are not relevant as we are not caching values
@@ -12907,17 +13457,22 @@ class ChainExpression extends NodeBase {
12907
13457
  hasEffects(context) {
12908
13458
  return this.expression.hasEffectsAsChainElement(context) === true;
12909
13459
  }
13460
+ includePath(path, context) {
13461
+ this.included = true;
13462
+ this.expression.includePath(path, context);
13463
+ }
12910
13464
  removeAnnotations(code) {
12911
13465
  this.expression.removeAnnotations(code);
12912
13466
  }
12913
- applyDeoptimizations() { }
12914
13467
  }
13468
+ ChainExpression.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
13469
+ ChainExpression.prototype.applyDeoptimizations = doNotDeoptimize;
12915
13470
 
12916
13471
  class ClassBodyScope extends ChildScope {
12917
13472
  constructor(parent, classNode) {
12918
13473
  const { context } = parent;
12919
13474
  super(parent, context);
12920
- this.variables.set('this', (this.thisVariable = new LocalVariable('this', null, classNode, context, 'other')));
13475
+ this.variables.set('this', (this.thisVariable = new LocalVariable('this', null, classNode, EMPTY_PATH, context, 'other')));
12921
13476
  this.instanceScope = new ChildScope(this, context);
12922
13477
  this.instanceScope.variables.set('this', new ThisVariable(context));
12923
13478
  }
@@ -12932,7 +13487,7 @@ class ClassBody extends NodeBase {
12932
13487
  }
12933
13488
  include(context, includeChildrenRecursively) {
12934
13489
  this.included = true;
12935
- this.scope.context.includeVariableInModule(this.scope.thisVariable);
13490
+ this.scope.context.includeVariableInModule(this.scope.thisVariable, UNKNOWN_PATH, context);
12936
13491
  for (const definition of this.body) {
12937
13492
  definition.include(context, includeChildrenRecursively);
12938
13493
  }
@@ -12945,8 +13500,9 @@ class ClassBody extends NodeBase {
12945
13500
  }
12946
13501
  return super.parseNode(esTreeNode);
12947
13502
  }
12948
- applyDeoptimizations() { }
12949
13503
  }
13504
+ ClassBody.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
13505
+ ClassBody.prototype.applyDeoptimizations = doNotDeoptimize;
12950
13506
 
12951
13507
  class ClassExpression extends ClassNode {
12952
13508
  render(code, options, { renderedSurroundingElement } = parseAst_js.BLANK) {
@@ -13017,6 +13573,9 @@ class ConditionalExpression extends NodeBase {
13017
13573
  const unusedBranch = this.usedBranch === this.consequent ? this.alternate : this.consequent;
13018
13574
  this.usedBranch = null;
13019
13575
  unusedBranch.deoptimizePath(UNKNOWN_PATH);
13576
+ if (this.included) {
13577
+ unusedBranch.includePath(UNKNOWN_PATH, createInclusionContext());
13578
+ }
13020
13579
  const { expressionsToBeDeoptimized } = this;
13021
13580
  this.expressionsToBeDeoptimized = parseAst_js.EMPTY_ARRAY;
13022
13581
  for (const expression of expressionsToBeDeoptimized) {
@@ -13074,7 +13633,7 @@ class ConditionalExpression extends NodeBase {
13074
13633
  include(context, includeChildrenRecursively) {
13075
13634
  this.included = true;
13076
13635
  const usedBranch = this.getUsedBranch();
13077
- if (includeChildrenRecursively || this.test.shouldBeIncluded(context) || usedBranch === null) {
13636
+ if (usedBranch === null || includeChildrenRecursively || this.test.shouldBeIncluded(context)) {
13078
13637
  this.test.include(context, includeChildrenRecursively);
13079
13638
  this.consequent.include(context, includeChildrenRecursively);
13080
13639
  this.alternate.include(context, includeChildrenRecursively);
@@ -13083,27 +13642,38 @@ class ConditionalExpression extends NodeBase {
13083
13642
  usedBranch.include(context, includeChildrenRecursively);
13084
13643
  }
13085
13644
  }
13086
- includeCallArguments(context, parameters) {
13645
+ includePath(path, context) {
13646
+ this.included = true;
13647
+ const usedBranch = this.getUsedBranch();
13648
+ if (usedBranch === null || this.test.shouldBeIncluded(context)) {
13649
+ this.consequent.includePath(path, context);
13650
+ this.alternate.includePath(path, context);
13651
+ }
13652
+ else {
13653
+ usedBranch.includePath(path, context);
13654
+ }
13655
+ }
13656
+ includeCallArguments(context, interaction) {
13087
13657
  const usedBranch = this.getUsedBranch();
13088
13658
  if (usedBranch) {
13089
- usedBranch.includeCallArguments(context, parameters);
13659
+ usedBranch.includeCallArguments(context, interaction);
13090
13660
  }
13091
13661
  else {
13092
- this.consequent.includeCallArguments(context, parameters);
13093
- this.alternate.includeCallArguments(context, parameters);
13662
+ this.consequent.includeCallArguments(context, interaction);
13663
+ this.alternate.includeCallArguments(context, interaction);
13094
13664
  }
13095
13665
  }
13096
13666
  removeAnnotations(code) {
13097
13667
  this.test.removeAnnotations(code);
13098
13668
  }
13099
13669
  render(code, options, { isCalleeOfRenderedParent, preventASI, renderedParentType, renderedSurroundingElement } = parseAst_js.BLANK) {
13100
- const usedBranch = this.getUsedBranch();
13101
13670
  if (this.test.included) {
13102
13671
  this.test.render(code, options, { renderedSurroundingElement });
13103
13672
  this.consequent.render(code, options);
13104
13673
  this.alternate.render(code, options);
13105
13674
  }
13106
13675
  else {
13676
+ const usedBranch = this.getUsedBranch();
13107
13677
  const colonPos = findFirstOccurrenceOutsideComment(code.original, ':', this.consequent.end);
13108
13678
  const inclusionStart = findNonWhiteSpace(code.original, (this.consequent.included
13109
13679
  ? findFirstOccurrenceOutsideComment(code.original, '?', this.test.end)
@@ -13135,6 +13705,8 @@ class ConditionalExpression extends NodeBase {
13135
13705
  : (this.usedBranch = testValue ? this.consequent : this.alternate);
13136
13706
  }
13137
13707
  }
13708
+ ConditionalExpression.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
13709
+ ConditionalExpression.prototype.applyDeoptimizations = doNotDeoptimize;
13138
13710
 
13139
13711
  class ContinueStatement extends NodeBase {
13140
13712
  hasEffects(context) {
@@ -13154,7 +13726,7 @@ class ContinueStatement extends NodeBase {
13154
13726
  include(context) {
13155
13727
  this.included = true;
13156
13728
  if (this.label) {
13157
- this.label.include();
13729
+ this.label.include(context);
13158
13730
  context.includedLabels.add(this.label.name);
13159
13731
  }
13160
13732
  else {
@@ -13163,12 +13735,15 @@ class ContinueStatement extends NodeBase {
13163
13735
  context.brokenFlow = true;
13164
13736
  }
13165
13737
  }
13738
+ ContinueStatement.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
13739
+ ContinueStatement.prototype.applyDeoptimizations = doNotDeoptimize;
13166
13740
 
13167
13741
  class DebuggerStatement extends NodeBase {
13168
13742
  hasEffects() {
13169
13743
  return true;
13170
13744
  }
13171
13745
  }
13746
+ DebuggerStatement.prototype.includeNode = onlyIncludeSelf;
13172
13747
 
13173
13748
  class Decorator extends NodeBase {
13174
13749
  hasEffects(context) {
@@ -13176,6 +13751,7 @@ class Decorator extends NodeBase {
13176
13751
  this.expression.hasEffectsOnInteractionAtPath(EMPTY_PATH, NODE_INTERACTION_UNKNOWN_CALL, context));
13177
13752
  }
13178
13753
  }
13754
+ Decorator.prototype.includeNode = onlyIncludeSelf;
13179
13755
 
13180
13756
  function hasLoopBodyEffects(context, body) {
13181
13757
  const { brokenFlow, hasBreak, hasContinue, ignore } = context;
@@ -13215,12 +13791,15 @@ class DoWhileStatement extends NodeBase {
13215
13791
  includeLoopBody(context, this.body, includeChildrenRecursively);
13216
13792
  }
13217
13793
  }
13794
+ DoWhileStatement.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
13795
+ DoWhileStatement.prototype.applyDeoptimizations = doNotDeoptimize;
13218
13796
 
13219
13797
  class EmptyStatement extends NodeBase {
13220
13798
  hasEffects() {
13221
13799
  return false;
13222
13800
  }
13223
13801
  }
13802
+ EmptyStatement.prototype.includeNode = onlyIncludeSelf;
13224
13803
 
13225
13804
  class ExportAllDeclaration extends NodeBase {
13226
13805
  hasEffects() {
@@ -13233,9 +13812,10 @@ class ExportAllDeclaration extends NodeBase {
13233
13812
  render(code, _options, nodeRenderOptions) {
13234
13813
  code.remove(nodeRenderOptions.start, nodeRenderOptions.end);
13235
13814
  }
13236
- applyDeoptimizations() { }
13237
13815
  }
13238
13816
  ExportAllDeclaration.prototype.needsBoundaries = true;
13817
+ ExportAllDeclaration.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
13818
+ ExportAllDeclaration.prototype.applyDeoptimizations = doNotDeoptimize;
13239
13819
 
13240
13820
  class ExportNamedDeclaration extends NodeBase {
13241
13821
  bind() {
@@ -13262,13 +13842,15 @@ class ExportNamedDeclaration extends NodeBase {
13262
13842
  this.declaration.render(code, options, { end, start });
13263
13843
  }
13264
13844
  }
13265
- applyDeoptimizations() { }
13266
13845
  }
13267
13846
  ExportNamedDeclaration.prototype.needsBoundaries = true;
13847
+ ExportNamedDeclaration.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
13848
+ ExportNamedDeclaration.prototype.applyDeoptimizations = doNotDeoptimize;
13268
13849
 
13269
13850
  class ExportSpecifier extends NodeBase {
13270
- applyDeoptimizations() { }
13271
13851
  }
13852
+ ExportSpecifier.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
13853
+ ExportSpecifier.prototype.applyDeoptimizations = doNotDeoptimize;
13272
13854
 
13273
13855
  class ForInStatement extends NodeBase {
13274
13856
  createScope(parentScope) {
@@ -13286,11 +13868,18 @@ class ForInStatement extends NodeBase {
13286
13868
  const { body, deoptimized, left, right } = this;
13287
13869
  if (!deoptimized)
13288
13870
  this.applyDeoptimizations();
13289
- this.included = true;
13871
+ if (!this.included)
13872
+ this.includeNode(context);
13290
13873
  left.includeAsAssignmentTarget(context, includeChildrenRecursively || true, false);
13291
13874
  right.include(context, includeChildrenRecursively);
13292
13875
  includeLoopBody(context, body, includeChildrenRecursively);
13293
13876
  }
13877
+ includeNode(context) {
13878
+ this.included = true;
13879
+ if (!this.deoptimized)
13880
+ this.applyDeoptimizations();
13881
+ this.right.includePath(UNKNOWN_PATH, context);
13882
+ }
13294
13883
  initialise() {
13295
13884
  super.initialise();
13296
13885
  this.left.setAssignedValue(UNKNOWN_EXPRESSION);
@@ -13331,11 +13920,18 @@ class ForOfStatement extends NodeBase {
13331
13920
  const { body, deoptimized, left, right } = this;
13332
13921
  if (!deoptimized)
13333
13922
  this.applyDeoptimizations();
13334
- this.included = true;
13923
+ if (!this.included)
13924
+ this.includeNode(context);
13335
13925
  left.includeAsAssignmentTarget(context, includeChildrenRecursively || true, false);
13336
13926
  right.include(context, includeChildrenRecursively);
13337
13927
  includeLoopBody(context, body, includeChildrenRecursively);
13338
13928
  }
13929
+ includeNode(context) {
13930
+ this.included = true;
13931
+ if (!this.deoptimized)
13932
+ this.applyDeoptimizations();
13933
+ this.right.includePath(UNKNOWN_PATH, context);
13934
+ }
13339
13935
  initialise() {
13340
13936
  super.initialise();
13341
13937
  this.left.setAssignedValue(UNKNOWN_EXPRESSION);
@@ -13371,7 +13967,9 @@ class ForStatement extends NodeBase {
13371
13967
  }
13372
13968
  include(context, includeChildrenRecursively) {
13373
13969
  this.included = true;
13374
- this.init?.include(context, includeChildrenRecursively, { asSingleStatement: true });
13970
+ this.init?.include(context, includeChildrenRecursively, {
13971
+ asSingleStatement: true
13972
+ });
13375
13973
  this.test?.include(context, includeChildrenRecursively);
13376
13974
  this.update?.include(context, includeChildrenRecursively);
13377
13975
  includeLoopBody(context, this.body, includeChildrenRecursively);
@@ -13383,6 +13981,8 @@ class ForStatement extends NodeBase {
13383
13981
  this.body.render(code, options);
13384
13982
  }
13385
13983
  }
13984
+ ForStatement.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
13985
+ ForStatement.prototype.applyDeoptimizations = doNotDeoptimize;
13386
13986
 
13387
13987
  class FunctionExpression extends FunctionNode {
13388
13988
  createScope(parentScope) {
@@ -13414,9 +14014,9 @@ class TrackingScope extends BlockScope {
13414
14014
  super(...arguments);
13415
14015
  this.hoistedDeclarations = [];
13416
14016
  }
13417
- addDeclaration(identifier, context, init, kind) {
14017
+ addDeclaration(identifier, context, init, destructuredInitPath, kind) {
13418
14018
  this.hoistedDeclarations.push(identifier);
13419
- return super.addDeclaration(identifier, context, init, kind);
14019
+ return super.addDeclaration(identifier, context, init, destructuredInitPath, kind);
13420
14020
  }
13421
14021
  }
13422
14022
 
@@ -13515,7 +14115,6 @@ class IfStatement extends NodeBase {
13515
14115
  }
13516
14116
  this.renderHoistedDeclarations(hoistedDeclarations, code, getPropertyAccess);
13517
14117
  }
13518
- applyDeoptimizations() { }
13519
14118
  getTestValue() {
13520
14119
  if (this.testValue === unset) {
13521
14120
  return (this.testValue = tryCastLiteralValueToBoolean(this.test.getLiteralValueAtPath(EMPTY_PATH, SHARED_RECURSION_TRACKER, this)));
@@ -13584,6 +14183,8 @@ class IfStatement extends NodeBase {
13584
14183
  return false;
13585
14184
  }
13586
14185
  }
14186
+ IfStatement.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
14187
+ IfStatement.prototype.applyDeoptimizations = doNotDeoptimize;
13587
14188
 
13588
14189
  class ImportAttribute extends NodeBase {
13589
14190
  }
@@ -13601,13 +14202,15 @@ class ImportDeclaration extends NodeBase {
13601
14202
  render(code, _options, nodeRenderOptions) {
13602
14203
  code.remove(nodeRenderOptions.start, nodeRenderOptions.end);
13603
14204
  }
13604
- applyDeoptimizations() { }
13605
14205
  }
13606
14206
  ImportDeclaration.prototype.needsBoundaries = true;
14207
+ ImportDeclaration.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
14208
+ ImportDeclaration.prototype.applyDeoptimizations = doNotDeoptimize;
13607
14209
 
13608
14210
  class ImportDefaultSpecifier extends NodeBase {
13609
- applyDeoptimizations() { }
13610
14211
  }
14212
+ ImportDefaultSpecifier.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
14213
+ ImportDefaultSpecifier.prototype.applyDeoptimizations = doNotDeoptimize;
13611
14214
 
13612
14215
  function isReassignedExportsMember(variable, exportNamesByVariable) {
13613
14216
  return (variable.renderBaseName !== null && exportNamesByVariable.has(variable) && variable.isReassigned);
@@ -13616,28 +14219,33 @@ function isReassignedExportsMember(variable, exportNamesByVariable) {
13616
14219
  class VariableDeclarator extends NodeBase {
13617
14220
  declareDeclarator(kind, isUsingDeclaration) {
13618
14221
  this.isUsingDeclaration = isUsingDeclaration;
13619
- this.id.declare(kind, this.init || UNDEFINED_EXPRESSION);
14222
+ this.id.declare(kind, EMPTY_PATH, this.init || UNDEFINED_EXPRESSION);
13620
14223
  }
13621
14224
  deoptimizePath(path) {
13622
14225
  this.id.deoptimizePath(path);
13623
14226
  }
13624
14227
  hasEffects(context) {
13625
- if (!this.deoptimized)
13626
- this.applyDeoptimizations();
13627
14228
  const initEffect = this.init?.hasEffects(context);
13628
14229
  this.id.markDeclarationReached();
13629
- return initEffect || this.id.hasEffects(context) || this.isUsingDeclaration;
14230
+ return (initEffect ||
14231
+ this.isUsingDeclaration ||
14232
+ this.id.hasEffects(context) ||
14233
+ (this.scope.context.options.treeshake
14234
+ .propertyReadSideEffects &&
14235
+ this.id.hasEffectsWhenDestructuring(context, EMPTY_PATH, this.init || UNDEFINED_EXPRESSION)));
13630
14236
  }
13631
14237
  include(context, includeChildrenRecursively) {
13632
- const { deoptimized, id, init } = this;
13633
- if (!deoptimized)
13634
- this.applyDeoptimizations();
13635
- this.included = true;
14238
+ const { id, init } = this;
14239
+ if (!this.included)
14240
+ this.includeNode();
13636
14241
  init?.include(context, includeChildrenRecursively);
13637
14242
  id.markDeclarationReached();
13638
- if (includeChildrenRecursively || id.shouldBeIncluded(context)) {
14243
+ if (includeChildrenRecursively) {
13639
14244
  id.include(context, includeChildrenRecursively);
13640
14245
  }
14246
+ else {
14247
+ id.includeDestructuredIfNecessary(context, EMPTY_PATH, init || UNDEFINED_EXPRESSION);
14248
+ }
13641
14249
  }
13642
14250
  removeAnnotations(code) {
13643
14251
  this.init?.removeAnnotations(code);
@@ -13667,8 +14275,8 @@ class VariableDeclarator extends NodeBase {
13667
14275
  code.appendLeft(end, `${_}=${_}void 0`);
13668
14276
  }
13669
14277
  }
13670
- applyDeoptimizations() {
13671
- this.deoptimized = true;
14278
+ includeNode() {
14279
+ this.included = true;
13672
14280
  const { id, init } = this;
13673
14281
  if (init && id instanceof Identifier && init instanceof ClassExpression && !init.id) {
13674
14282
  const { name, variable } = id;
@@ -13680,11 +14288,14 @@ class VariableDeclarator extends NodeBase {
13680
14288
  }
13681
14289
  }
13682
14290
  }
14291
+ VariableDeclarator.prototype.applyDeoptimizations = doNotDeoptimize;
13683
14292
 
13684
14293
  class ImportExpression extends NodeBase {
13685
14294
  constructor() {
13686
14295
  super(...arguments);
13687
14296
  this.inlineNamespace = null;
14297
+ this.hasUnknownAccessedKey = false;
14298
+ this.accessedPropKey = new Set();
13688
14299
  this.attributes = null;
13689
14300
  this.mechanism = null;
13690
14301
  this.namespaceExportName = undefined;
@@ -13717,12 +14328,15 @@ class ImportExpression extends NodeBase {
13717
14328
  if (parent2 instanceof ExpressionStatement) {
13718
14329
  return parseAst_js.EMPTY_ARRAY;
13719
14330
  }
13720
- // Case 1: const { foo } = await import('bar')
14331
+ // Case 1: const { foo } / module = await import('bar')
13721
14332
  if (parent2 instanceof VariableDeclarator) {
13722
14333
  const declaration = parent2.id;
13723
- return declaration instanceof ObjectPattern
13724
- ? getDeterministicObjectDestructure(declaration)
13725
- : undefined;
14334
+ if (declaration instanceof Identifier) {
14335
+ return this.hasUnknownAccessedKey ? undefined : [...this.accessedPropKey];
14336
+ }
14337
+ if (declaration instanceof ObjectPattern) {
14338
+ return getDeterministicObjectDestructure(declaration);
14339
+ }
13726
14340
  }
13727
14341
  // Case 2: (await import('bar')).foo
13728
14342
  if (parent2 instanceof MemberExpression) {
@@ -13772,13 +14386,30 @@ class ImportExpression extends NodeBase {
13772
14386
  return true;
13773
14387
  }
13774
14388
  include(context, includeChildrenRecursively) {
13775
- if (!this.included) {
13776
- this.included = true;
13777
- this.scope.context.includeDynamicImport(this);
13778
- this.scope.addAccessedDynamicImport(this);
13779
- }
14389
+ if (!this.included)
14390
+ this.includeNode();
13780
14391
  this.source.include(context, includeChildrenRecursively);
13781
14392
  }
14393
+ includeNode() {
14394
+ this.included = true;
14395
+ this.scope.context.includeDynamicImport(this);
14396
+ this.scope.addAccessedDynamicImport(this);
14397
+ }
14398
+ includePath(path) {
14399
+ if (!this.included)
14400
+ this.includeNode();
14401
+ // Technically, this is not correct as dynamic imports return a Promise.
14402
+ if (this.hasUnknownAccessedKey)
14403
+ return;
14404
+ if (path[0] === UnknownKey) {
14405
+ this.hasUnknownAccessedKey = true;
14406
+ }
14407
+ else if (typeof path[0] === 'string') {
14408
+ this.accessedPropKey.add(path[0]);
14409
+ }
14410
+ // Update included paths
14411
+ this.scope.context.includeDynamicImport(this);
14412
+ }
13782
14413
  initialise() {
13783
14414
  super.initialise();
13784
14415
  this.scope.context.addDynamicImport(this);
@@ -13847,7 +14478,6 @@ class ImportExpression extends NodeBase {
13847
14478
  setInternalResolution(inlineNamespace) {
13848
14479
  this.inlineNamespace = inlineNamespace;
13849
14480
  }
13850
- applyDeoptimizations() { }
13851
14481
  getDynamicImportMechanismAndHelper(resolution, exportMode, { compact, dynamicImportInCjs, format, generatedCode: { arrowFunctions }, interop }, { _, getDirectReturnFunction, getDirectReturnIifeLeft }, pluginDriver) {
13852
14482
  const mechanism = pluginDriver.hookFirstSync('renderDynamicImport', [
13853
14483
  {
@@ -13937,6 +14567,7 @@ class ImportExpression extends NodeBase {
13937
14567
  return { helper: null, mechanism: null };
13938
14568
  }
13939
14569
  }
14570
+ ImportExpression.prototype.applyDeoptimizations = doNotDeoptimize;
13940
14571
  function getInteropHelper(resolution, exportMode, interop) {
13941
14572
  return exportMode === 'external'
13942
14573
  ? namespaceInteropHelpersByInteropType[interop(resolution instanceof ExternalModule ? resolution.id : null)]
@@ -13960,12 +14591,14 @@ function getDeterministicObjectDestructure(objectPattern) {
13960
14591
  }
13961
14592
 
13962
14593
  class ImportNamespaceSpecifier extends NodeBase {
13963
- applyDeoptimizations() { }
13964
14594
  }
14595
+ ImportNamespaceSpecifier.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
14596
+ ImportNamespaceSpecifier.prototype.applyDeoptimizations = doNotDeoptimize;
13965
14597
 
13966
14598
  class ImportSpecifier extends NodeBase {
13967
- applyDeoptimizations() { }
13968
14599
  }
14600
+ ImportSpecifier.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
14601
+ ImportSpecifier.prototype.applyDeoptimizations = doNotDeoptimize;
13969
14602
 
13970
14603
  class JSXIdentifier extends IdentifierBase {
13971
14604
  constructor() {
@@ -13982,6 +14615,29 @@ class JSXIdentifier extends IdentifierBase {
13982
14615
  this.isNativeElement = true;
13983
14616
  }
13984
14617
  }
14618
+ include(context) {
14619
+ if (!this.included)
14620
+ this.includeNode(context);
14621
+ }
14622
+ includeNode(context) {
14623
+ this.included = true;
14624
+ if (!this.deoptimized)
14625
+ this.applyDeoptimizations();
14626
+ if (this.variable !== null) {
14627
+ this.scope.context.includeVariableInModule(this.variable, EMPTY_PATH, context);
14628
+ }
14629
+ }
14630
+ includePath(path, context) {
14631
+ if (!this.included) {
14632
+ this.included = true;
14633
+ if (this.variable !== null) {
14634
+ this.scope.context.includeVariableInModule(this.variable, path, context);
14635
+ }
14636
+ }
14637
+ else if (path.length > 0) {
14638
+ this.variable?.includePath(path, context);
14639
+ }
14640
+ }
13985
14641
  render(code, { snippets: { getPropertyAccess }, useOriginalName }) {
13986
14642
  if (this.variable) {
13987
14643
  const name = this.variable.getName(getPropertyAccess, useOriginalName);
@@ -14043,6 +14699,7 @@ class JSXAttribute extends NodeBase {
14043
14699
  }
14044
14700
  }
14045
14701
  }
14702
+ JSXAttribute.prototype.includeNode = onlyIncludeSelf;
14046
14703
 
14047
14704
  class JSXClosingBase extends NodeBase {
14048
14705
  render(code, options) {
@@ -14055,6 +14712,7 @@ class JSXClosingBase extends NodeBase {
14055
14712
  }
14056
14713
  }
14057
14714
  }
14715
+ JSXClosingBase.prototype.includeNode = onlyIncludeSelf;
14058
14716
 
14059
14717
  class JSXClosingElement extends JSXClosingBase {
14060
14718
  }
@@ -14075,8 +14733,15 @@ class JSXSpreadAttribute extends NodeBase {
14075
14733
 
14076
14734
  class JSXEmptyExpression extends NodeBase {
14077
14735
  }
14736
+ JSXEmptyExpression.prototype.includeNode = onlyIncludeSelf;
14078
14737
 
14079
14738
  class JSXExpressionContainer extends NodeBase {
14739
+ includeNode(context) {
14740
+ this.included = true;
14741
+ if (!this.deoptimized)
14742
+ this.applyDeoptimizations();
14743
+ this.expression.includePath(UNKNOWN_PATH, context);
14744
+ }
14080
14745
  render(code, options) {
14081
14746
  const { mode } = this.scope.context.options.jsx;
14082
14747
  if (mode !== 'preserve') {
@@ -14097,7 +14762,7 @@ function getRenderedJsxChildren(children) {
14097
14762
  return renderedChildren;
14098
14763
  }
14099
14764
 
14100
- function getAndIncludeFactoryVariable(factory, preserve, importSource, node) {
14765
+ function getAndIncludeFactoryVariable(factory, preserve, importSource, node, context) {
14101
14766
  const [baseName, nestedName] = factory.split('.');
14102
14767
  let factoryVariable;
14103
14768
  if (importSource) {
@@ -14105,7 +14770,7 @@ function getAndIncludeFactoryVariable(factory, preserve, importSource, node) {
14105
14770
  if (preserve) {
14106
14771
  // This pretends we are accessing an included global variable of the same name
14107
14772
  const globalVariable = node.scope.findGlobal(baseName);
14108
- globalVariable.include();
14773
+ globalVariable.includePath(UNKNOWN_PATH, context);
14109
14774
  // This excludes this variable from renaming
14110
14775
  factoryVariable.globalName = baseName;
14111
14776
  }
@@ -14113,7 +14778,7 @@ function getAndIncludeFactoryVariable(factory, preserve, importSource, node) {
14113
14778
  else {
14114
14779
  factoryVariable = node.scope.findGlobal(baseName);
14115
14780
  }
14116
- node.scope.context.includeVariableInModule(factoryVariable);
14781
+ node.scope.context.includeVariableInModule(factoryVariable, UNKNOWN_PATH, context);
14117
14782
  if (factoryVariable instanceof LocalVariable) {
14118
14783
  factoryVariable.consolidateInitializers();
14119
14784
  factoryVariable.addUsedPlace(node);
@@ -14136,16 +14801,20 @@ class JSXElementBase extends NodeBase {
14136
14801
  }
14137
14802
  }
14138
14803
  include(context, includeChildrenRecursively) {
14139
- if (!this.included) {
14140
- const { factory, importSource, mode } = this.jsxMode;
14141
- if (factory) {
14142
- this.factory = factory;
14143
- this.factoryVariable = getAndIncludeFactoryVariable(factory, mode === 'preserve', importSource, this);
14144
- }
14804
+ if (!this.included)
14805
+ this.includeNode(context);
14806
+ for (const child of this.children) {
14807
+ child.include(context, includeChildrenRecursively);
14808
+ }
14809
+ }
14810
+ includeNode(context) {
14811
+ this.included = true;
14812
+ const { factory, importSource, mode } = this.jsxMode;
14813
+ if (factory) {
14814
+ this.factory = factory;
14815
+ this.factoryVariable = getAndIncludeFactoryVariable(factory, mode === 'preserve', importSource, this, context);
14145
14816
  }
14146
- super.include(context, includeChildrenRecursively);
14147
14817
  }
14148
- applyDeoptimizations() { }
14149
14818
  getRenderingMode() {
14150
14819
  const jsx = this.scope.context.options.jsx;
14151
14820
  const { mode, factory, importSource } = jsx;
@@ -14183,8 +14852,14 @@ class JSXElementBase extends NodeBase {
14183
14852
  return { childrenEnd, firstChild, hasMultipleChildren };
14184
14853
  }
14185
14854
  }
14855
+ JSXElementBase.prototype.applyDeoptimizations = doNotDeoptimize;
14186
14856
 
14187
14857
  class JSXElement extends JSXElementBase {
14858
+ include(context, includeChildrenRecursively) {
14859
+ super.include(context, includeChildrenRecursively);
14860
+ this.openingElement.include(context, includeChildrenRecursively);
14861
+ this.closingElement?.include(context, includeChildrenRecursively);
14862
+ }
14188
14863
  render(code, options) {
14189
14864
  switch (this.jsxMode.mode) {
14190
14865
  case 'classic': {
@@ -14336,6 +15011,11 @@ class JSXElement extends JSXElementBase {
14336
15011
  }
14337
15012
 
14338
15013
  class JSXFragment extends JSXElementBase {
15014
+ include(context, includeChildrenRecursively) {
15015
+ super.include(context, includeChildrenRecursively);
15016
+ this.openingFragment.include(context, includeChildrenRecursively);
15017
+ this.closingFragment.include(context, includeChildrenRecursively);
15018
+ }
14339
15019
  render(code, options) {
14340
15020
  switch (this.jsxMode.mode) {
14341
15021
  case 'classic': {
@@ -14385,10 +15065,22 @@ class JSXFragment extends JSXElementBase {
14385
15065
  }
14386
15066
 
14387
15067
  class JSXMemberExpression extends NodeBase {
15068
+ includeNode(context) {
15069
+ this.included = true;
15070
+ if (!this.deoptimized)
15071
+ this.applyDeoptimizations();
15072
+ this.object.includePath([this.property.name], context);
15073
+ }
15074
+ includePath(path, context) {
15075
+ if (!this.included)
15076
+ this.includeNode(context);
15077
+ this.object.includePath([this.property.name, ...path], context);
15078
+ }
14388
15079
  }
14389
15080
 
14390
15081
  class JSXNamespacedName extends NodeBase {
14391
15082
  }
15083
+ JSXNamespacedName.prototype.includeNode = onlyIncludeSelf;
14392
15084
 
14393
15085
  class JSXOpeningElement extends NodeBase {
14394
15086
  render(code, options, { jsxMode = this.scope.context.options.jsx.mode } = {}) {
@@ -14398,6 +15090,7 @@ class JSXOpeningElement extends NodeBase {
14398
15090
  }
14399
15091
  }
14400
15092
  }
15093
+ JSXOpeningElement.prototype.includeNode = onlyIncludeSelf;
14401
15094
 
14402
15095
  class JSXOpeningFragment extends NodeBase {
14403
15096
  constructor() {
@@ -14405,22 +15098,22 @@ class JSXOpeningFragment extends NodeBase {
14405
15098
  this.fragment = null;
14406
15099
  this.fragmentVariable = null;
14407
15100
  }
14408
- include(context, includeChildrenRecursively) {
14409
- if (!this.included) {
14410
- const jsx = this.scope.context.options.jsx;
14411
- if (jsx.mode === 'automatic') {
14412
- this.fragment = 'Fragment';
14413
- this.fragmentVariable = getAndIncludeFactoryVariable('Fragment', false, jsx.jsxImportSource, this);
14414
- }
14415
- else {
14416
- const { fragment, importSource, mode } = jsx;
14417
- if (fragment != null) {
14418
- this.fragment = fragment;
14419
- this.fragmentVariable = getAndIncludeFactoryVariable(fragment, mode === 'preserve', importSource, this);
14420
- }
15101
+ includeNode(context) {
15102
+ this.included = true;
15103
+ if (!this.deoptimized)
15104
+ this.applyDeoptimizations();
15105
+ const jsx = this.scope.context.options.jsx;
15106
+ if (jsx.mode === 'automatic') {
15107
+ this.fragment = 'Fragment';
15108
+ this.fragmentVariable = getAndIncludeFactoryVariable('Fragment', false, jsx.jsxImportSource, this, context);
15109
+ }
15110
+ else {
15111
+ const { fragment, importSource, mode } = jsx;
15112
+ if (fragment != null) {
15113
+ this.fragment = fragment;
15114
+ this.fragmentVariable = getAndIncludeFactoryVariable(fragment, mode === 'preserve', importSource, this, context);
14421
15115
  }
14422
15116
  }
14423
- super.include(context, includeChildrenRecursively);
14424
15117
  }
14425
15118
  render(code, options) {
14426
15119
  const { mode } = this.scope.context.options.jsx;
@@ -14457,6 +15150,7 @@ class JSXText extends NodeBase {
14457
15150
  }
14458
15151
  }
14459
15152
  }
15153
+ JSXText.prototype.includeNode = onlyIncludeSelf;
14460
15154
 
14461
15155
  class LabeledStatement extends NodeBase {
14462
15156
  hasEffects(context) {
@@ -14478,17 +15172,22 @@ class LabeledStatement extends NodeBase {
14478
15172
  return bodyHasEffects;
14479
15173
  }
14480
15174
  include(context, includeChildrenRecursively) {
14481
- this.included = true;
15175
+ if (!this.included)
15176
+ this.includeNode(context);
14482
15177
  const { brokenFlow, includedLabels } = context;
14483
15178
  context.includedLabels = new Set();
14484
15179
  this.body.include(context, includeChildrenRecursively);
14485
15180
  if (includeChildrenRecursively || context.includedLabels.has(this.label.name)) {
14486
- this.label.include();
15181
+ this.label.include(context);
14487
15182
  context.includedLabels.delete(this.label.name);
14488
15183
  context.brokenFlow = brokenFlow;
14489
15184
  }
14490
15185
  context.includedLabels = new Set([...includedLabels, ...context.includedLabels]);
14491
15186
  }
15187
+ includeNode(context) {
15188
+ this.included = true;
15189
+ this.body.includePath(UNKNOWN_PATH, context);
15190
+ }
14492
15191
  render(code, options) {
14493
15192
  if (this.label.included) {
14494
15193
  this.label.render(code, options);
@@ -14499,6 +15198,7 @@ class LabeledStatement extends NodeBase {
14499
15198
  this.body.render(code, options);
14500
15199
  }
14501
15200
  }
15201
+ LabeledStatement.prototype.applyDeoptimizations = doNotDeoptimize;
14502
15202
 
14503
15203
  class LogicalExpression extends NodeBase {
14504
15204
  constructor() {
@@ -14515,10 +15215,10 @@ class LogicalExpression extends NodeBase {
14515
15215
  this.flags = setFlag(this.flags, 65536 /* Flag.isBranchResolutionAnalysed */, value);
14516
15216
  }
14517
15217
  get hasDeoptimizedCache() {
14518
- return isFlagSet(this.flags, 16777216 /* Flag.hasDeoptimizedCache */);
15218
+ return isFlagSet(this.flags, 33554432 /* Flag.hasDeoptimizedCache */);
14519
15219
  }
14520
15220
  set hasDeoptimizedCache(value) {
14521
- this.flags = setFlag(this.flags, 16777216 /* Flag.hasDeoptimizedCache */, value);
15221
+ this.flags = setFlag(this.flags, 33554432 /* Flag.hasDeoptimizedCache */, value);
14522
15222
  }
14523
15223
  deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
14524
15224
  this.left.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
@@ -14532,6 +15232,10 @@ class LogicalExpression extends NodeBase {
14532
15232
  const unusedBranch = this.usedBranch === this.left ? this.right : this.left;
14533
15233
  this.usedBranch = null;
14534
15234
  unusedBranch.deoptimizePath(UNKNOWN_PATH);
15235
+ if (this.included) {
15236
+ // As we are not tracking inclusions, we just include everything
15237
+ unusedBranch.includePath(UNKNOWN_PATH, createInclusionContext());
15238
+ }
14535
15239
  }
14536
15240
  const { scope: { context }, expressionsToBeDeoptimized } = this;
14537
15241
  this.expressionsToBeDeoptimized = parseAst_js.EMPTY_ARRAY;
@@ -14576,16 +15280,17 @@ class LogicalExpression extends NodeBase {
14576
15280
  }
14577
15281
  getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin) {
14578
15282
  const usedBranch = this.getUsedBranch();
14579
- if (!usedBranch)
14580
- return [
14581
- new MultiExpression([
14582
- this.left.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)[0],
14583
- this.right.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)[0]
14584
- ]),
14585
- false
14586
- ];
14587
- this.expressionsToBeDeoptimized.push(origin);
14588
- return usedBranch.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
15283
+ if (usedBranch) {
15284
+ this.expressionsToBeDeoptimized.push(origin);
15285
+ return usedBranch.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin);
15286
+ }
15287
+ return [
15288
+ new MultiExpression([
15289
+ this.left.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)[0],
15290
+ this.right.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)[0]
15291
+ ]),
15292
+ false
15293
+ ];
14589
15294
  }
14590
15295
  hasEffects(context) {
14591
15296
  if (this.left.hasEffects(context)) {
@@ -14598,18 +15303,18 @@ class LogicalExpression extends NodeBase {
14598
15303
  }
14599
15304
  hasEffectsOnInteractionAtPath(path, interaction, context) {
14600
15305
  const usedBranch = this.getUsedBranch();
14601
- if (!usedBranch) {
14602
- return (this.left.hasEffectsOnInteractionAtPath(path, interaction, context) ||
14603
- this.right.hasEffectsOnInteractionAtPath(path, interaction, context));
15306
+ if (usedBranch) {
15307
+ return usedBranch.hasEffectsOnInteractionAtPath(path, interaction, context);
14604
15308
  }
14605
- return usedBranch.hasEffectsOnInteractionAtPath(path, interaction, context);
15309
+ return (this.left.hasEffectsOnInteractionAtPath(path, interaction, context) ||
15310
+ this.right.hasEffectsOnInteractionAtPath(path, interaction, context));
14606
15311
  }
14607
15312
  include(context, includeChildrenRecursively) {
14608
15313
  this.included = true;
14609
15314
  const usedBranch = this.getUsedBranch();
14610
15315
  if (includeChildrenRecursively ||
14611
- (usedBranch === this.right && this.left.shouldBeIncluded(context)) ||
14612
- !usedBranch) {
15316
+ !usedBranch ||
15317
+ (usedBranch === this.right && this.left.shouldBeIncluded(context))) {
14613
15318
  this.left.include(context, includeChildrenRecursively);
14614
15319
  this.right.include(context, includeChildrenRecursively);
14615
15320
  }
@@ -14617,6 +15322,17 @@ class LogicalExpression extends NodeBase {
14617
15322
  usedBranch.include(context, includeChildrenRecursively);
14618
15323
  }
14619
15324
  }
15325
+ includePath(path, context) {
15326
+ this.included = true;
15327
+ const usedBranch = this.getUsedBranch();
15328
+ if (!usedBranch || (usedBranch === this.right && this.left.shouldBeIncluded(context))) {
15329
+ this.left.includePath(path, context);
15330
+ this.right.includePath(path, context);
15331
+ }
15332
+ else {
15333
+ usedBranch.includePath(path, context);
15334
+ }
15335
+ }
14620
15336
  removeAnnotations(code) {
14621
15337
  this.left.removeAnnotations(code);
14622
15338
  }
@@ -14669,6 +15385,8 @@ class LogicalExpression extends NodeBase {
14669
15385
  return this.usedBranch;
14670
15386
  }
14671
15387
  }
15388
+ LogicalExpression.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
15389
+ LogicalExpression.prototype.applyDeoptimizations = doNotDeoptimize;
14672
15390
 
14673
15391
  class NewExpression extends NodeBase {
14674
15392
  hasEffects(context) {
@@ -14688,16 +15406,21 @@ class NewExpression extends NodeBase {
14688
15406
  return path.length > 0 || type !== INTERACTION_ACCESSED;
14689
15407
  }
14690
15408
  include(context, includeChildrenRecursively) {
14691
- if (!this.deoptimized)
14692
- this.applyDeoptimizations();
14693
15409
  if (includeChildrenRecursively) {
14694
15410
  super.include(context, includeChildrenRecursively);
14695
15411
  }
14696
15412
  else {
14697
- this.included = true;
15413
+ if (!this.included)
15414
+ this.includeNode(context);
14698
15415
  this.callee.include(context, false);
14699
15416
  }
14700
- this.callee.includeCallArguments(context, this.arguments);
15417
+ this.callee.includeCallArguments(context, this.interaction);
15418
+ }
15419
+ includeNode(context) {
15420
+ this.included = true;
15421
+ if (!this.deoptimized)
15422
+ this.applyDeoptimizations();
15423
+ this.callee.includePath(UNKNOWN_PATH, context);
14701
15424
  }
14702
15425
  initialise() {
14703
15426
  super.initialise();
@@ -14726,6 +15449,7 @@ class ObjectExpression extends NodeBase {
14726
15449
  constructor() {
14727
15450
  super(...arguments);
14728
15451
  this.objectEntity = null;
15452
+ this.protoProp = null;
14729
15453
  }
14730
15454
  deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
14731
15455
  this.getObjectEntity().deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
@@ -14745,15 +15469,43 @@ class ObjectExpression extends NodeBase {
14745
15469
  hasEffectsOnInteractionAtPath(path, interaction, context) {
14746
15470
  return this.getObjectEntity().hasEffectsOnInteractionAtPath(path, interaction, context);
14747
15471
  }
15472
+ include(context, includeChildrenRecursively) {
15473
+ if (!this.included)
15474
+ this.includeNode(context);
15475
+ this.getObjectEntity().include(context, includeChildrenRecursively);
15476
+ this.protoProp?.include(context, includeChildrenRecursively);
15477
+ }
15478
+ includeNode(context) {
15479
+ this.included = true;
15480
+ this.protoProp?.includePath(UNKNOWN_PATH, context);
15481
+ }
15482
+ includePath(path, context) {
15483
+ if (!this.included)
15484
+ this.includeNode(context);
15485
+ this.getObjectEntity().includePath(path, context);
15486
+ }
14748
15487
  render(code, options, { renderedSurroundingElement } = parseAst_js.BLANK) {
14749
- super.render(code, options);
14750
15488
  if (renderedSurroundingElement === parseAst_js.ExpressionStatement ||
14751
15489
  renderedSurroundingElement === parseAst_js.ArrowFunctionExpression) {
14752
15490
  code.appendRight(this.start, '(');
14753
15491
  code.prependLeft(this.end, ')');
14754
15492
  }
15493
+ if (this.properties.length > 0) {
15494
+ const separatedNodes = getCommaSeparatedNodesWithBoundaries(this.properties, code, this.start + 1, this.end - 1);
15495
+ let lastSeparatorPos = null;
15496
+ for (const { node, separator, start, end } of separatedNodes) {
15497
+ if (!node.included) {
15498
+ treeshakeNode(node, code, start, end);
15499
+ continue;
15500
+ }
15501
+ lastSeparatorPos = separator;
15502
+ node.render(code, options);
15503
+ }
15504
+ if (lastSeparatorPos) {
15505
+ code.remove(lastSeparatorPos, this.end - 1);
15506
+ }
15507
+ }
14755
15508
  }
14756
- applyDeoptimizations() { }
14757
15509
  getObjectEntity() {
14758
15510
  if (this.objectEntity !== null) {
14759
15511
  return this.objectEntity;
@@ -14782,6 +15534,7 @@ class ObjectExpression extends NodeBase {
14782
15534
  ? property.key.name
14783
15535
  : String(property.key.value);
14784
15536
  if (key === '__proto__' && property.kind === 'init') {
15537
+ this.protoProp = property;
14785
15538
  prototype =
14786
15539
  property.value instanceof Literal && property.value.value === null
14787
15540
  ? null
@@ -14794,6 +15547,7 @@ class ObjectExpression extends NodeBase {
14794
15547
  return (this.objectEntity = new ObjectEntity(properties, prototype));
14795
15548
  }
14796
15549
  }
15550
+ ObjectExpression.prototype.applyDeoptimizations = doNotDeoptimize;
14797
15551
 
14798
15552
  class PanicError extends NodeBase {
14799
15553
  initialise() {
@@ -14820,6 +15574,7 @@ class ParseError extends NodeBase {
14820
15574
 
14821
15575
  class PrivateIdentifier extends NodeBase {
14822
15576
  }
15577
+ PrivateIdentifier.prototype.includeNode = onlyIncludeSelf;
14823
15578
 
14824
15579
  class Program extends NodeBase {
14825
15580
  constructor() {
@@ -14887,14 +15642,11 @@ class Program extends NodeBase {
14887
15642
  super.render(code, options);
14888
15643
  }
14889
15644
  }
14890
- applyDeoptimizations() { }
14891
15645
  }
15646
+ Program.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
15647
+ Program.prototype.applyDeoptimizations = doNotDeoptimize;
14892
15648
 
14893
15649
  class Property extends MethodBase {
14894
- constructor() {
14895
- super(...arguments);
14896
- this.declarationInit = null;
14897
- }
14898
15650
  //declare method: boolean;
14899
15651
  get method() {
14900
15652
  return isFlagSet(this.flags, 262144 /* Flag.method */);
@@ -14909,17 +15661,41 @@ class Property extends MethodBase {
14909
15661
  set shorthand(value) {
14910
15662
  this.flags = setFlag(this.flags, 524288 /* Flag.shorthand */, value);
14911
15663
  }
14912
- declare(kind, init) {
14913
- this.declarationInit = init;
14914
- return this.value.declare(kind, UNKNOWN_EXPRESSION);
15664
+ declare(kind, destructuredInitPath, init) {
15665
+ return this.value.declare(kind, this.getPathInProperty(destructuredInitPath), init);
15666
+ }
15667
+ deoptimizeAssignment(destructuredInitPath, init) {
15668
+ this.value.deoptimizeAssignment?.(this.getPathInProperty(destructuredInitPath), init);
14915
15669
  }
14916
15670
  hasEffects(context) {
14917
- if (!this.deoptimized)
14918
- this.applyDeoptimizations();
14919
- const propertyReadSideEffects = this.scope.context.options.treeshake.propertyReadSideEffects;
14920
- return ((this.parent.type === 'ObjectPattern' && propertyReadSideEffects === 'always') ||
14921
- this.key.hasEffects(context) ||
14922
- this.value.hasEffects(context));
15671
+ return this.key.hasEffects(context) || this.value.hasEffects(context);
15672
+ }
15673
+ hasEffectsWhenDestructuring(context, destructuredInitPath, init) {
15674
+ return this.value.hasEffectsWhenDestructuring?.(context, this.getPathInProperty(destructuredInitPath), init);
15675
+ }
15676
+ includeDestructuredIfNecessary(context, destructuredInitPath, init) {
15677
+ const path = this.getPathInProperty(destructuredInitPath);
15678
+ let included = this.value.includeDestructuredIfNecessary(context, path, init) ||
15679
+ this.included;
15680
+ if ((included ||= this.key.hasEffects(createHasEffectsContext()))) {
15681
+ this.key.include(context, false);
15682
+ if (!this.value.included) {
15683
+ this.value.included = true;
15684
+ // Unfortunately, we need to include the value again now, so that any
15685
+ // declared variables are properly included.
15686
+ this.value.includeDestructuredIfNecessary(context, path, init);
15687
+ }
15688
+ }
15689
+ return (this.included = included);
15690
+ }
15691
+ include(context, includeChildrenRecursively) {
15692
+ this.included = true;
15693
+ this.key.include(context, includeChildrenRecursively);
15694
+ this.value.include(context, includeChildrenRecursively);
15695
+ }
15696
+ includePath(path, context) {
15697
+ this.included = true;
15698
+ this.value.includePath(path, context);
14923
15699
  }
14924
15700
  markDeclarationReached() {
14925
15701
  this.value.markDeclarationReached();
@@ -14930,14 +15706,20 @@ class Property extends MethodBase {
14930
15706
  }
14931
15707
  this.value.render(code, options, { isShorthandProperty: this.shorthand });
14932
15708
  }
14933
- applyDeoptimizations() {
14934
- this.deoptimized = true;
14935
- if (this.declarationInit !== null) {
14936
- this.declarationInit.deoptimizePath([UnknownKey, UnknownKey]);
14937
- this.scope.context.requestTreeshakingPass();
14938
- }
15709
+ getPathInProperty(destructuredInitPath) {
15710
+ return destructuredInitPath.at(-1) === UnknownKey
15711
+ ? destructuredInitPath
15712
+ : // For now, we only consider static paths as we do not know how to
15713
+ // deoptimize the path in the dynamic case.
15714
+ this.computed
15715
+ ? [...destructuredInitPath, UnknownKey]
15716
+ : this.key instanceof Identifier
15717
+ ? [...destructuredInitPath, this.key.name]
15718
+ : [...destructuredInitPath, String(this.key.value)];
14939
15719
  }
14940
15720
  }
15721
+ Property.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
15722
+ Property.prototype.applyDeoptimizations = doNotDeoptimize;
14941
15723
 
14942
15724
  class PropertyDefinition extends NodeBase {
14943
15725
  get computed() {
@@ -14970,8 +15752,15 @@ class PropertyDefinition extends NodeBase {
14970
15752
  hasEffectsOnInteractionAtPath(path, interaction, context) {
14971
15753
  return !this.value || this.value.hasEffectsOnInteractionAtPath(path, interaction, context);
14972
15754
  }
14973
- applyDeoptimizations() { }
15755
+ includeNode(context) {
15756
+ this.included = true;
15757
+ this.value?.includePath(UNKNOWN_PATH, context);
15758
+ for (const decorator of this.decorators) {
15759
+ decorator.includePath(UNKNOWN_PATH, context);
15760
+ }
15761
+ }
14974
15762
  }
15763
+ PropertyDefinition.prototype.applyDeoptimizations = doNotDeoptimize;
14975
15764
 
14976
15765
  class ReturnStatement extends NodeBase {
14977
15766
  hasEffects(context) {
@@ -14981,10 +15770,15 @@ class ReturnStatement extends NodeBase {
14981
15770
  return false;
14982
15771
  }
14983
15772
  include(context, includeChildrenRecursively) {
14984
- this.included = true;
15773
+ if (!this.included)
15774
+ this.includeNode(context);
14985
15775
  this.argument?.include(context, includeChildrenRecursively);
14986
15776
  context.brokenFlow = true;
14987
15777
  }
15778
+ includeNode(context) {
15779
+ this.included = true;
15780
+ this.argument?.includePath(UNKNOWN_PATH, context);
15781
+ }
14988
15782
  initialise() {
14989
15783
  super.initialise();
14990
15784
  this.scope.addReturnExpression(this.argument || UNKNOWN_EXPRESSION);
@@ -14998,6 +15792,7 @@ class ReturnStatement extends NodeBase {
14998
15792
  }
14999
15793
  }
15000
15794
  }
15795
+ ReturnStatement.prototype.applyDeoptimizations = doNotDeoptimize;
15001
15796
 
15002
15797
  class SequenceExpression extends NodeBase {
15003
15798
  deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker) {
@@ -15025,10 +15820,15 @@ class SequenceExpression extends NodeBase {
15025
15820
  for (const expression of this.expressions) {
15026
15821
  if (includeChildrenRecursively ||
15027
15822
  (expression === lastExpression && !(this.parent instanceof ExpressionStatement)) ||
15028
- expression.shouldBeIncluded(context))
15823
+ expression.shouldBeIncluded(context)) {
15029
15824
  expression.include(context, includeChildrenRecursively);
15825
+ }
15030
15826
  }
15031
15827
  }
15828
+ includePath(path, context) {
15829
+ this.included = true;
15830
+ this.expressions[this.expressions.length - 1].includePath(path, context);
15831
+ }
15032
15832
  removeAnnotations(code) {
15033
15833
  this.expressions[0].removeAnnotations(code);
15034
15834
  }
@@ -15063,6 +15863,8 @@ class SequenceExpression extends NodeBase {
15063
15863
  }
15064
15864
  }
15065
15865
  }
15866
+ SequenceExpression.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
15867
+ SequenceExpression.prototype.applyDeoptimizations = doNotDeoptimize;
15066
15868
 
15067
15869
  class Super extends NodeBase {
15068
15870
  bind() {
@@ -15074,11 +15876,15 @@ class Super extends NodeBase {
15074
15876
  deoptimizePath(path) {
15075
15877
  this.variable.deoptimizePath(path);
15076
15878
  }
15077
- include() {
15078
- if (!this.included) {
15079
- this.included = true;
15080
- this.scope.context.includeVariableInModule(this.variable);
15081
- }
15879
+ include(context) {
15880
+ if (!this.included)
15881
+ this.includeNode(context);
15882
+ }
15883
+ includeNode(context) {
15884
+ this.included = true;
15885
+ if (!this.deoptimized)
15886
+ this.applyDeoptimizations();
15887
+ this.scope.context.includeVariableInModule(this.variable, EMPTY_PATH, context);
15082
15888
  }
15083
15889
  }
15084
15890
 
@@ -15119,6 +15925,8 @@ class SwitchCase extends NodeBase {
15119
15925
  }
15120
15926
  }
15121
15927
  SwitchCase.prototype.needsBoundaries = true;
15928
+ SwitchCase.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
15929
+ SwitchCase.prototype.applyDeoptimizations = doNotDeoptimize;
15122
15930
 
15123
15931
  class SwitchStatement extends NodeBase {
15124
15932
  createScope(parentScope) {
@@ -15201,6 +16009,8 @@ class SwitchStatement extends NodeBase {
15201
16009
  }
15202
16010
  }
15203
16011
  }
16012
+ SwitchStatement.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
16013
+ SwitchStatement.prototype.applyDeoptimizations = doNotDeoptimize;
15204
16014
 
15205
16015
  class TaggedTemplateExpression extends CallExpressionBase {
15206
16016
  bind() {
@@ -15224,8 +16034,8 @@ class TaggedTemplateExpression extends CallExpressionBase {
15224
16034
  this.tag.hasEffectsOnInteractionAtPath(EMPTY_PATH, this.interaction, context));
15225
16035
  }
15226
16036
  include(context, includeChildrenRecursively) {
15227
- if (!this.deoptimized)
15228
- this.applyDeoptimizations();
16037
+ if (!this.included)
16038
+ this.includeNode(context);
15229
16039
  if (includeChildrenRecursively) {
15230
16040
  super.include(context, includeChildrenRecursively);
15231
16041
  }
@@ -15234,7 +16044,7 @@ class TaggedTemplateExpression extends CallExpressionBase {
15234
16044
  this.tag.include(context, includeChildrenRecursively);
15235
16045
  this.quasi.include(context, includeChildrenRecursively);
15236
16046
  }
15237
- this.tag.includeCallArguments(context, this.args);
16047
+ this.tag.includeCallArguments(context, this.interaction);
15238
16048
  const [returnExpression] = this.getReturnExpression();
15239
16049
  if (!returnExpression.included) {
15240
16050
  returnExpression.include(context, false);
@@ -15269,6 +16079,7 @@ class TaggedTemplateExpression extends CallExpressionBase {
15269
16079
  return this.returnExpression;
15270
16080
  }
15271
16081
  }
16082
+ TaggedTemplateExpression.prototype.includeNode = onlyIncludeSelf;
15272
16083
 
15273
16084
  class TemplateElement extends NodeBase {
15274
16085
  get tail() {
@@ -15282,15 +16093,13 @@ class TemplateElement extends NodeBase {
15282
16093
  hasEffects() {
15283
16094
  return false;
15284
16095
  }
15285
- include() {
15286
- this.included = true;
15287
- }
15288
16096
  parseNode(esTreeNode) {
15289
16097
  this.value = esTreeNode.value;
15290
16098
  return super.parseNode(esTreeNode);
15291
16099
  }
15292
16100
  render() { }
15293
16101
  }
16102
+ TemplateElement.prototype.includeNode = onlyIncludeSelf;
15294
16103
 
15295
16104
  class TemplateLiteral extends NodeBase {
15296
16105
  deoptimizeArgumentsOnInteractionAtPath() { }
@@ -15315,6 +16124,14 @@ class TemplateLiteral extends NodeBase {
15315
16124
  }
15316
16125
  return true;
15317
16126
  }
16127
+ includeNode(context) {
16128
+ this.included = true;
16129
+ if (!this.deoptimized)
16130
+ this.applyDeoptimizations();
16131
+ for (const node of this.expressions) {
16132
+ node.includePath(UNKNOWN_PATH, context);
16133
+ }
16134
+ }
15318
16135
  render(code, options) {
15319
16136
  code.indentExclusionRanges.push([this.start, this.end]);
15320
16137
  super.render(code, options);
@@ -15324,13 +16141,13 @@ class TemplateLiteral extends NodeBase {
15324
16141
  class ModuleScope extends ChildScope {
15325
16142
  constructor(parent, context) {
15326
16143
  super(parent, context);
15327
- this.variables.set('this', new LocalVariable('this', null, UNDEFINED_EXPRESSION, context, 'other'));
16144
+ this.variables.set('this', new LocalVariable('this', null, UNDEFINED_EXPRESSION, EMPTY_PATH, context, 'other'));
15328
16145
  }
15329
- addDeclaration(identifier, context, init, kind) {
16146
+ addDeclaration(identifier, context, init, destructuredInitPath, kind) {
15330
16147
  if (this.context.module.importDescriptions.has(identifier.name)) {
15331
16148
  context.error(parseAst_js.logRedeclarationError(identifier.name), identifier.start);
15332
16149
  }
15333
- return super.addDeclaration(identifier, context, init, kind);
16150
+ return super.addDeclaration(identifier, context, init, destructuredInitPath, kind);
15334
16151
  }
15335
16152
  addExportDefaultDeclaration(name, exportDefaultDeclaration, context) {
15336
16153
  const variable = new ExportDefaultVariable(name, exportDefaultDeclaration, context);
@@ -15375,10 +16192,23 @@ class ThisExpression extends NodeBase {
15375
16192
  }
15376
16193
  return this.variable.hasEffectsOnInteractionAtPath(path, interaction, context);
15377
16194
  }
15378
- include() {
16195
+ include(context) {
16196
+ if (!this.included)
16197
+ this.includeNode(context);
16198
+ }
16199
+ includeNode(context) {
16200
+ this.included = true;
16201
+ if (!this.deoptimized)
16202
+ this.applyDeoptimizations();
16203
+ this.scope.context.includeVariableInModule(this.variable, EMPTY_PATH, context);
16204
+ }
16205
+ includePath(path, context) {
15379
16206
  if (!this.included) {
15380
16207
  this.included = true;
15381
- this.scope.context.includeVariableInModule(this.variable);
16208
+ this.scope.context.includeVariableInModule(this.variable, path, context);
16209
+ }
16210
+ else if (path.length > 0) {
16211
+ this.variable.includePath(path, context);
15382
16212
  }
15383
16213
  }
15384
16214
  initialise() {
@@ -15406,7 +16236,8 @@ class ThrowStatement extends NodeBase {
15406
16236
  return true;
15407
16237
  }
15408
16238
  include(context, includeChildrenRecursively) {
15409
- this.included = true;
16239
+ if (!this.included)
16240
+ this.includeNode(context);
15410
16241
  this.argument.include(context, includeChildrenRecursively);
15411
16242
  context.brokenFlow = true;
15412
16243
  }
@@ -15417,6 +16248,7 @@ class ThrowStatement extends NodeBase {
15417
16248
  }
15418
16249
  }
15419
16250
  }
16251
+ ThrowStatement.prototype.includeNode = onlyIncludeSelf;
15420
16252
 
15421
16253
  class TryStatement extends NodeBase {
15422
16254
  constructor() {
@@ -15453,6 +16285,8 @@ class TryStatement extends NodeBase {
15453
16285
  this.finalizer?.include(context, includeChildrenRecursively);
15454
16286
  }
15455
16287
  }
16288
+ TryStatement.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
16289
+ TryStatement.prototype.applyDeoptimizations = doNotDeoptimize;
15456
16290
 
15457
16291
  const unaryOperators = {
15458
16292
  '!': value => !value,
@@ -15559,6 +16393,7 @@ function getSimplifiedNumber(value) {
15559
16393
  const stringifiedValue = String(value).replace('+', '');
15560
16394
  return finalizedExp.length < stringifiedValue.length ? finalizedExp : stringifiedValue;
15561
16395
  }
16396
+ UnaryExpression.prototype.includeNode = onlyIncludeSelf;
15562
16397
 
15563
16398
  class UpdateExpression extends NodeBase {
15564
16399
  hasEffects(context) {
@@ -15570,9 +16405,8 @@ class UpdateExpression extends NodeBase {
15570
16405
  return path.length > 1 || type !== INTERACTION_ACCESSED;
15571
16406
  }
15572
16407
  include(context, includeChildrenRecursively) {
15573
- if (!this.deoptimized)
15574
- this.applyDeoptimizations();
15575
- this.included = true;
16408
+ if (!this.included)
16409
+ this.includeNode(context);
15576
16410
  this.argument.includeAsAssignmentTarget(context, includeChildrenRecursively, true);
15577
16411
  }
15578
16412
  initialise() {
@@ -15611,6 +16445,7 @@ class UpdateExpression extends NodeBase {
15611
16445
  this.scope.context.requestTreeshakingPass();
15612
16446
  }
15613
16447
  }
16448
+ UpdateExpression.prototype.includeNode = onlyIncludeSelf;
15614
16449
 
15615
16450
  function areAllDeclarationsIncludedAndNotExported(declarations, exportNamesByVariable) {
15616
16451
  for (const declarator of declarations) {
@@ -15641,8 +16476,9 @@ class VariableDeclaration extends NodeBase {
15641
16476
  include(context, includeChildrenRecursively, { asSingleStatement } = parseAst_js.BLANK) {
15642
16477
  this.included = true;
15643
16478
  for (const declarator of this.declarations) {
15644
- if (includeChildrenRecursively || declarator.shouldBeIncluded(context))
16479
+ if (includeChildrenRecursively || declarator.shouldBeIncluded(context)) {
15645
16480
  declarator.include(context, includeChildrenRecursively);
16481
+ }
15646
16482
  const { id, init } = declarator;
15647
16483
  if (asSingleStatement) {
15648
16484
  id.include(context, includeChildrenRecursively);
@@ -15680,7 +16516,6 @@ class VariableDeclaration extends NodeBase {
15680
16516
  this.renderReplacedDeclarations(code, options);
15681
16517
  }
15682
16518
  }
15683
- applyDeoptimizations() { }
15684
16519
  renderDeclarationEnd(code, separatorString, lastSeparatorPos, actualContentEnd, renderedContentEnd, systemPatternExports, options) {
15685
16520
  if (code.original.charCodeAt(this.end - 1) === 59 /*";"*/) {
15686
16521
  code.remove(this.end - 1, this.end);
@@ -15723,8 +16558,7 @@ class VariableDeclaration extends NodeBase {
15723
16558
  const singleSystemExport = gatherSystemExportsAndGetSingleExport(separatedNodes, options, aggregatedSystemExports);
15724
16559
  for (const { node, start, separator, contentEnd, end } of separatedNodes) {
15725
16560
  if (!node.included) {
15726
- code.remove(start, end);
15727
- node.removeAnnotations(code);
16561
+ treeshakeNode(node, code, start, end);
15728
16562
  continue;
15729
16563
  }
15730
16564
  node.render(code, options);
@@ -15794,6 +16628,8 @@ function gatherSystemExportsAndGetSingleExport(separatedNodes, options, aggregat
15794
16628
  }
15795
16629
  return singleSystemExport;
15796
16630
  }
16631
+ VariableDeclaration.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
16632
+ VariableDeclaration.prototype.applyDeoptimizations = doNotDeoptimize;
15797
16633
 
15798
16634
  class WhileStatement extends NodeBase {
15799
16635
  hasEffects(context) {
@@ -15807,13 +16643,25 @@ class WhileStatement extends NodeBase {
15807
16643
  includeLoopBody(context, this.body, includeChildrenRecursively);
15808
16644
  }
15809
16645
  }
16646
+ WhileStatement.prototype.includeNode = onlyIncludeSelfNoDeoptimize;
16647
+ WhileStatement.prototype.applyDeoptimizations = doNotDeoptimize;
15810
16648
 
15811
16649
  class YieldExpression extends NodeBase {
16650
+ applyDeoptimizations() {
16651
+ this.deoptimized = true;
16652
+ this.argument?.deoptimizePath(UNKNOWN_PATH);
16653
+ }
15812
16654
  hasEffects(context) {
15813
16655
  if (!this.deoptimized)
15814
16656
  this.applyDeoptimizations();
15815
16657
  return !(context.ignore.returnYield && !this.argument?.hasEffects(context));
15816
16658
  }
16659
+ includeNode(context) {
16660
+ this.included = true;
16661
+ if (!this.deoptimized)
16662
+ this.applyDeoptimizations();
16663
+ this.argument?.includePath(UNKNOWN_PATH, context);
16664
+ }
15817
16665
  render(code, options) {
15818
16666
  if (this.argument) {
15819
16667
  this.argument.render(code, options, { preventASI: true });
@@ -16047,7 +16895,7 @@ const bufferParsers = [
16047
16895
  const annotations = (node.annotations = parseAst_js.convertAnnotations(buffer[position + 1], buffer));
16048
16896
  node.annotationNoSideEffects = annotations.some(comment => comment.type === 'noSideEffects');
16049
16897
  const parameters = (node.params = convertNodeList(node, scope, buffer[position + 2], buffer));
16050
- scope.addParameterVariables(parameters.map(parameter => parameter.declare('parameter', UNKNOWN_EXPRESSION)), parameters[parameters.length - 1] instanceof RestElement);
16898
+ scope.addParameterVariables(parameters.map(parameter => parameter.declare('parameter', EMPTY_PATH, UNKNOWN_EXPRESSION)), parameters[parameters.length - 1] instanceof RestElement);
16051
16899
  node.body = convertNode(node, scope.bodyScope, buffer[position + 3], buffer);
16052
16900
  },
16053
16901
  function assignmentExpression(node, position, buffer) {
@@ -16093,7 +16941,7 @@ const bufferParsers = [
16093
16941
  const parameterPosition = buffer[position];
16094
16942
  const parameter = (node.param =
16095
16943
  parameterPosition === 0 ? null : convertNode(node, scope, parameterPosition, buffer));
16096
- parameter?.declare('parameter', UNKNOWN_EXPRESSION);
16944
+ parameter?.declare('parameter', EMPTY_PATH, UNKNOWN_EXPRESSION);
16097
16945
  node.body = convertNode(node, scope.bodyScope, buffer[position + 1], buffer);
16098
16946
  },
16099
16947
  function chainExpression(node, position, buffer) {
@@ -16231,7 +17079,7 @@ const bufferParsers = [
16231
17079
  node.id =
16232
17080
  idPosition === 0 ? null : convertNode(node, scope.parent, idPosition, buffer);
16233
17081
  const parameters = (node.params = convertNodeList(node, scope, buffer[position + 3], buffer));
16234
- scope.addParameterVariables(parameters.map(parameter => parameter.declare('parameter', UNKNOWN_EXPRESSION)), parameters[parameters.length - 1] instanceof RestElement);
17082
+ scope.addParameterVariables(parameters.map(parameter => parameter.declare('parameter', EMPTY_PATH, UNKNOWN_EXPRESSION)), parameters[parameters.length - 1] instanceof RestElement);
16235
17083
  node.body = convertNode(node, scope.bodyScope, buffer[position + 4], buffer);
16236
17084
  },
16237
17085
  function functionExpression(node, position, buffer) {
@@ -16244,7 +17092,7 @@ const bufferParsers = [
16244
17092
  const idPosition = buffer[position + 2];
16245
17093
  node.id = idPosition === 0 ? null : convertNode(node, node.idScope, idPosition, buffer);
16246
17094
  const parameters = (node.params = convertNodeList(node, scope, buffer[position + 3], buffer));
16247
- scope.addParameterVariables(parameters.map(parameter => parameter.declare('parameter', UNKNOWN_EXPRESSION)), parameters[parameters.length - 1] instanceof RestElement);
17095
+ scope.addParameterVariables(parameters.map(parameter => parameter.declare('parameter', EMPTY_PATH, UNKNOWN_EXPRESSION)), parameters[parameters.length - 1] instanceof RestElement);
16248
17096
  node.body = convertNode(node, scope.bodyScope, buffer[position + 4], buffer);
16249
17097
  },
16250
17098
  function identifier(node, position, buffer) {
@@ -16708,8 +17556,8 @@ class ExportShimVariable extends Variable {
16708
17556
  super(MISSING_EXPORT_SHIM_VARIABLE);
16709
17557
  this.module = module;
16710
17558
  }
16711
- include() {
16712
- super.include();
17559
+ includePath(path, context) {
17560
+ super.includePath(path, context);
16713
17561
  this.module.needsExportShim = true;
16714
17562
  }
16715
17563
  }
@@ -17400,16 +18248,15 @@ class Module {
17400
18248
  markModuleAndImpureDependenciesAsExecuted(this);
17401
18249
  this.graph.needsTreeshakingPass = true;
17402
18250
  }
18251
+ const inclusionContext = createInclusionContext();
17403
18252
  for (const exportName of this.exports.keys()) {
17404
18253
  if (includeNamespaceMembers || exportName !== this.info.syntheticNamedExports) {
17405
18254
  const variable = this.getVariableForExportName(exportName)[0];
17406
18255
  if (!variable) {
17407
18256
  return parseAst_js.error(parseAst_js.logMissingEntryExport(exportName, this.id));
17408
18257
  }
18258
+ this.includeVariable(variable, UNKNOWN_PATH, inclusionContext);
17409
18259
  variable.deoptimizePath(UNKNOWN_PATH);
17410
- if (!variable.included) {
17411
- this.includeVariable(variable);
17412
- }
17413
18260
  }
17414
18261
  }
17415
18262
  for (const name of this.getReexports()) {
@@ -17417,7 +18264,7 @@ class Module {
17417
18264
  if (variable) {
17418
18265
  variable.deoptimizePath(UNKNOWN_PATH);
17419
18266
  if (!variable.included) {
17420
- this.includeVariable(variable);
18267
+ this.includeVariable(variable, UNKNOWN_PATH, inclusionContext);
17421
18268
  }
17422
18269
  if (variable instanceof ExternalVariable) {
17423
18270
  variable.module.reexported = true;
@@ -17438,13 +18285,12 @@ class Module {
17438
18285
  this.graph.needsTreeshakingPass = true;
17439
18286
  }
17440
18287
  let includeNamespaceMembers = false;
18288
+ const inclusionContext = createInclusionContext();
17441
18289
  for (const name of names) {
17442
18290
  const variable = this.getVariableForExportName(name)[0];
17443
18291
  if (variable) {
17444
18292
  variable.deoptimizePath(UNKNOWN_PATH);
17445
- if (!variable.included) {
17446
- this.includeVariable(variable);
17447
- }
18293
+ this.includeVariable(variable, UNKNOWN_PATH, inclusionContext);
17448
18294
  }
17449
18295
  if (!this.exports.has(name) && !this.reexportDescriptions.has(name)) {
17450
18296
  includeNamespaceMembers = true;
@@ -17545,6 +18391,7 @@ class Module {
17545
18391
  manualPureFunctions: this.graph.pureFunctions,
17546
18392
  module: this,
17547
18393
  moduleContext: this.context,
18394
+ newlyIncludedVariableInits: this.graph.newlyIncludedVariableInits,
17548
18395
  options: this.options,
17549
18396
  requestTreeshakingPass: () => (this.graph.needsTreeshakingPass = true),
17550
18397
  traceExport: (name) => this.getVariableForExportName(name)[0],
@@ -17885,13 +18732,13 @@ class Module {
17885
18732
  for (const module of [this, ...this.exportAllModules]) {
17886
18733
  if (module instanceof ExternalModule) {
17887
18734
  const [externalVariable] = module.getVariableForExportName('*');
17888
- externalVariable.include();
18735
+ externalVariable.includePath(UNKNOWN_PATH, createInclusionContext());
17889
18736
  this.includedImports.add(externalVariable);
17890
18737
  externalNamespaces.add(externalVariable);
17891
18738
  }
17892
18739
  else if (module.info.syntheticNamedExports) {
17893
18740
  const syntheticNamespace = module.getSyntheticNamespace();
17894
- syntheticNamespace.include();
18741
+ syntheticNamespace.includePath(UNKNOWN_PATH, createInclusionContext());
17895
18742
  this.includedImports.add(syntheticNamespace);
17896
18743
  syntheticNamespaces.add(syntheticNamespace);
17897
18744
  }
@@ -17901,7 +18748,9 @@ class Module {
17901
18748
  includeDynamicImport(node) {
17902
18749
  const resolution = this.dynamicImports.find(dynamicImport => dynamicImport.node === node).resolution;
17903
18750
  if (resolution instanceof Module) {
17904
- resolution.includedDynamicImporters.push(this);
18751
+ if (!resolution.includedDynamicImporters.includes(this)) {
18752
+ resolution.includedDynamicImporters.push(this);
18753
+ }
17905
18754
  const importedNames = this.options.treeshake
17906
18755
  ? node.getDeterministicImportedNames()
17907
18756
  : undefined;
@@ -17913,15 +18762,15 @@ class Module {
17913
18762
  }
17914
18763
  }
17915
18764
  }
17916
- includeVariable(variable) {
17917
- const variableModule = variable.module;
17918
- if (variable.included) {
18765
+ includeVariable(variable, path, context) {
18766
+ const { included, module: variableModule } = variable;
18767
+ variable.includePath(path, context);
18768
+ if (included) {
17919
18769
  if (variableModule instanceof Module && variableModule !== this) {
17920
18770
  getAndExtendSideEffectModules(variable, this);
17921
18771
  }
17922
18772
  }
17923
18773
  else {
17924
- variable.include();
17925
18774
  this.graph.needsTreeshakingPass = true;
17926
18775
  if (variableModule instanceof Module) {
17927
18776
  if (!variableModule.isExecuted) {
@@ -17938,8 +18787,8 @@ class Module {
17938
18787
  }
17939
18788
  }
17940
18789
  }
17941
- includeVariableInModule(variable) {
17942
- this.includeVariable(variable);
18790
+ includeVariableInModule(variable, path, context) {
18791
+ this.includeVariable(variable, path, context);
17943
18792
  const variableModule = variable.module;
17944
18793
  if (variableModule && variableModule !== this) {
17945
18794
  this.includedImports.add(variable);
@@ -21448,10 +22297,11 @@ class Graph {
21448
22297
  this.options = options;
21449
22298
  this.astLru = flru(5);
21450
22299
  this.cachedModules = new Map();
21451
- this.deoptimizationTracker = new PathTracker();
22300
+ this.deoptimizationTracker = new EntityPathTracker();
21452
22301
  this.entryModules = [];
21453
22302
  this.modulesById = new Map();
21454
22303
  this.needsTreeshakingPass = false;
22304
+ this.newlyIncludedVariableInits = new Set();
21455
22305
  this.phase = BuildPhase.LOAD_AND_PARSE;
21456
22306
  this.scope = new GlobalScope();
21457
22307
  this.watchFiles = Object.create(null);
@@ -21545,6 +22395,7 @@ class Graph {
21545
22395
  }
21546
22396
  if (this.options.treeshake) {
21547
22397
  let treeshakingPass = 1;
22398
+ this.newlyIncludedVariableInits.clear();
21548
22399
  do {
21549
22400
  timeStart(`treeshaking pass ${treeshakingPass}`, 3);
21550
22401
  this.needsTreeshakingPass = false;
@@ -21557,6 +22408,10 @@ class Graph {
21557
22408
  else {
21558
22409
  module.include();
21559
22410
  }
22411
+ for (const entity of this.newlyIncludedVariableInits) {
22412
+ this.newlyIncludedVariableInits.delete(entity);
22413
+ entity.include(createInclusionContext(), false);
22414
+ }
21560
22415
  }
21561
22416
  }
21562
22417
  if (treeshakingPass === 1) {