mirror of https://github.com/rollup/rollup.git
parent
fc99e96e09
commit
17437940f2
@ -1,147 +0,0 @@
|
||||
import type { CallOptions } from '../../CallOptions';
|
||||
import type { DeoptimizableEntity } from '../../DeoptimizableEntity';
|
||||
import type { HasEffectsContext } from '../../ExecutionContext';
|
||||
import { type NodeEvent } from '../../NodeEvents';
|
||||
import { type ObjectPath, type PathTracker, UNKNOWN_PATH } from '../../utils/PathTracker';
|
||||
import {
|
||||
type ExpressionEntity,
|
||||
type LiteralValueOrUnknown,
|
||||
UNKNOWN_EXPRESSION,
|
||||
UnknownValue
|
||||
} from './Expression';
|
||||
import { NodeBase } from './Node';
|
||||
|
||||
export default abstract class CallExpressionBase extends NodeBase implements DeoptimizableEntity {
|
||||
protected declare callOptions: CallOptions;
|
||||
protected deoptimized = false;
|
||||
protected returnExpression: ExpressionEntity | null = null;
|
||||
private readonly deoptimizableDependentExpressions: DeoptimizableEntity[] = [];
|
||||
private readonly expressionsToBeDeoptimized = new Set<ExpressionEntity>();
|
||||
|
||||
deoptimizeCache(): void {
|
||||
if (this.returnExpression !== UNKNOWN_EXPRESSION) {
|
||||
this.returnExpression = UNKNOWN_EXPRESSION;
|
||||
for (const expression of this.deoptimizableDependentExpressions) {
|
||||
expression.deoptimizeCache();
|
||||
}
|
||||
for (const expression of this.expressionsToBeDeoptimized) {
|
||||
expression.deoptimizePath(UNKNOWN_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deoptimizePath(path: ObjectPath): void {
|
||||
if (
|
||||
path.length === 0 ||
|
||||
this.context.deoptimizationTracker.trackEntityAtPathAndGetIfTracked(path, this)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const returnExpression = this.getReturnExpression();
|
||||
if (returnExpression !== UNKNOWN_EXPRESSION) {
|
||||
returnExpression.deoptimizePath(path);
|
||||
}
|
||||
}
|
||||
|
||||
deoptimizeThisOnEventAtPath(
|
||||
event: NodeEvent,
|
||||
path: ObjectPath,
|
||||
thisParameter: ExpressionEntity,
|
||||
recursionTracker: PathTracker
|
||||
): void {
|
||||
const returnExpression = this.getReturnExpression(recursionTracker);
|
||||
if (returnExpression === UNKNOWN_EXPRESSION) {
|
||||
thisParameter.deoptimizePath(UNKNOWN_PATH);
|
||||
} else {
|
||||
recursionTracker.withTrackedEntityAtPath(
|
||||
path,
|
||||
returnExpression,
|
||||
() => {
|
||||
this.expressionsToBeDeoptimized.add(thisParameter);
|
||||
returnExpression.deoptimizeThisOnEventAtPath(
|
||||
event,
|
||||
path,
|
||||
thisParameter,
|
||||
recursionTracker
|
||||
);
|
||||
},
|
||||
undefined
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getLiteralValueAtPath(
|
||||
path: ObjectPath,
|
||||
recursionTracker: PathTracker,
|
||||
origin: DeoptimizableEntity
|
||||
): LiteralValueOrUnknown {
|
||||
const returnExpression = this.getReturnExpression(recursionTracker);
|
||||
if (returnExpression === UNKNOWN_EXPRESSION) {
|
||||
return UnknownValue;
|
||||
}
|
||||
return recursionTracker.withTrackedEntityAtPath(
|
||||
path,
|
||||
returnExpression,
|
||||
() => {
|
||||
this.deoptimizableDependentExpressions.push(origin);
|
||||
return returnExpression.getLiteralValueAtPath(path, recursionTracker, origin);
|
||||
},
|
||||
UnknownValue
|
||||
);
|
||||
}
|
||||
|
||||
getReturnExpressionWhenCalledAtPath(
|
||||
path: ObjectPath,
|
||||
callOptions: CallOptions,
|
||||
recursionTracker: PathTracker,
|
||||
origin: DeoptimizableEntity
|
||||
): ExpressionEntity {
|
||||
const returnExpression = this.getReturnExpression(recursionTracker);
|
||||
if (this.returnExpression === UNKNOWN_EXPRESSION) {
|
||||
return UNKNOWN_EXPRESSION;
|
||||
}
|
||||
return recursionTracker.withTrackedEntityAtPath(
|
||||
path,
|
||||
returnExpression,
|
||||
() => {
|
||||
this.deoptimizableDependentExpressions.push(origin);
|
||||
return returnExpression.getReturnExpressionWhenCalledAtPath(
|
||||
path,
|
||||
callOptions,
|
||||
recursionTracker,
|
||||
origin
|
||||
);
|
||||
},
|
||||
UNKNOWN_EXPRESSION
|
||||
);
|
||||
}
|
||||
|
||||
hasEffectsWhenAccessedAtPath(path: ObjectPath, context: HasEffectsContext): boolean | undefined {
|
||||
return (
|
||||
!context.accessed.trackEntityAtPathAndGetIfTracked(path, this) &&
|
||||
this.getReturnExpression().hasEffectsWhenAccessedAtPath(path, context)
|
||||
);
|
||||
}
|
||||
|
||||
hasEffectsWhenAssignedAtPath(path: ObjectPath, context: HasEffectsContext): boolean {
|
||||
return (
|
||||
!context.assigned.trackEntityAtPathAndGetIfTracked(path, this) &&
|
||||
this.getReturnExpression().hasEffectsWhenAssignedAtPath(path, context)
|
||||
);
|
||||
}
|
||||
|
||||
hasEffectsWhenCalledAtPath(
|
||||
path: ObjectPath,
|
||||
callOptions: CallOptions,
|
||||
context: HasEffectsContext
|
||||
): boolean {
|
||||
return (
|
||||
!(
|
||||
callOptions.withNew ? context.instantiated : context.called
|
||||
).trackEntityAtPathAndGetIfTracked(path, callOptions, this) &&
|
||||
this.getReturnExpression().hasEffectsWhenCalledAtPath(path, callOptions, context)
|
||||
);
|
||||
}
|
||||
|
||||
protected abstract getReturnExpression(recursionTracker?: PathTracker): ExpressionEntity;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
define((function () { 'use strict';
|
||||
|
||||
function foo () {
|
||||
var Object = {
|
||||
keys: function () {
|
||||
console.log( 'side-effect' );
|
||||
}
|
||||
};
|
||||
|
||||
var obj = { foo: 1, bar: 2 };
|
||||
Object.keys( obj );
|
||||
}
|
||||
|
||||
foo();
|
||||
|
||||
var main = 42;
|
||||
|
||||
return main;
|
||||
|
||||
}));
|
@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
function foo () {
|
||||
var Object = {
|
||||
keys: function () {
|
||||
console.log( 'side-effect' );
|
||||
}
|
||||
};
|
||||
|
||||
var obj = { foo: 1, bar: 2 };
|
||||
Object.keys( obj );
|
||||
}
|
||||
|
||||
foo();
|
||||
|
||||
var main = 42;
|
||||
|
||||
module.exports = main;
|
@ -0,0 +1,21 @@
|
||||
var myBundle = (function () {
|
||||
'use strict';
|
||||
|
||||
function foo () {
|
||||
var Object = {
|
||||
keys: function () {
|
||||
console.log( 'side-effect' );
|
||||
}
|
||||
};
|
||||
|
||||
var obj = { foo: 1, bar: 2 };
|
||||
Object.keys( obj );
|
||||
}
|
||||
|
||||
foo();
|
||||
|
||||
var main = 42;
|
||||
|
||||
return main;
|
||||
|
||||
})();
|
@ -0,0 +1,23 @@
|
||||
System.register('myBundle', [], (function (exports) {
|
||||
'use strict';
|
||||
return {
|
||||
execute: (function () {
|
||||
|
||||
function foo () {
|
||||
var Object = {
|
||||
keys: function () {
|
||||
console.log( 'side-effect' );
|
||||
}
|
||||
};
|
||||
|
||||
var obj = { foo: 1, bar: 2 };
|
||||
Object.keys( obj );
|
||||
}
|
||||
|
||||
foo();
|
||||
|
||||
var main = exports('default', 42);
|
||||
|
||||
})
|
||||
};
|
||||
}));
|
@ -0,0 +1,24 @@
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.myBundle = factory());
|
||||
})(this, (function () { 'use strict';
|
||||
|
||||
function foo () {
|
||||
var Object = {
|
||||
keys: function () {
|
||||
console.log( 'side-effect' );
|
||||
}
|
||||
};
|
||||
|
||||
var obj = { foo: 1, bar: 2 };
|
||||
Object.keys( obj );
|
||||
}
|
||||
|
||||
foo();
|
||||
|
||||
var main = 42;
|
||||
|
||||
return main;
|
||||
|
||||
}));
|
@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
description: 'supports tree-shaking for unused default parameter values on arrays'
|
||||
};
|
@ -1,16 +0,0 @@
|
||||
var isUndefined;
|
||||
|
||||
const test2 = [
|
||||
(a = 'retained') => console.log(a)
|
||||
];
|
||||
|
||||
const test = [
|
||||
(a = 'retained', b = 'retained', c, d) => console.log(a, b, c),
|
||||
...test2,
|
||||
(a = 'retained') => console.log(a)
|
||||
];
|
||||
|
||||
test[0](isUndefined, 'b', 'c');
|
||||
test[0]('a', globalThis.unknown, 'c');
|
||||
test[1]();
|
||||
test[2]();
|
@ -1,16 +0,0 @@
|
||||
var isUndefined;
|
||||
|
||||
const test2 = [
|
||||
(a = 'retained') => console.log(a)
|
||||
];
|
||||
|
||||
const test = [
|
||||
(a = 'retained', b = 'retained', c = 'removed', d = 'removed') => console.log(a, b, c),
|
||||
...test2,
|
||||
(a = 'retained') => console.log(a)
|
||||
];
|
||||
|
||||
test[0](isUndefined, 'b', 'c');
|
||||
test[0]('a', globalThis.unknown, 'c');
|
||||
test[1]();
|
||||
test[2]();
|
@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
description: 'supports tree-shaking for unused default parameter values on classes'
|
||||
};
|
@ -1,29 +0,0 @@
|
||||
var isUndefined;
|
||||
|
||||
class Test {
|
||||
constructor(a = 'retained', b = 'retained', c, d) {
|
||||
console.log(a, b, c);
|
||||
}
|
||||
|
||||
method(a = 'retained') {
|
||||
console.log(a);
|
||||
}
|
||||
|
||||
prop = (a = 'retained') => console.log(a);
|
||||
|
||||
static staticMethod(a = 'retained', b = 'retained', c, d) {
|
||||
console.log(a, b, c);
|
||||
}
|
||||
|
||||
static staticProp = (a = 'retained', b = 'retained', c, d) =>
|
||||
console.log(a, b, c);
|
||||
}
|
||||
|
||||
new Test(isUndefined, 'b', 'c');
|
||||
new Test('a', globalThis.unknown, 'c').method();
|
||||
|
||||
Test.staticMethod(isUndefined, 'b', 'c');
|
||||
Test.staticMethod('a', globalThis.unknown, 'c');
|
||||
|
||||
Test.staticProp(isUndefined, 'b', 'c');
|
||||
Test.staticProp('a', globalThis.unknown, 'c');
|
@ -1,29 +0,0 @@
|
||||
var isUndefined;
|
||||
|
||||
class Test {
|
||||
constructor(a = 'retained', b = 'retained', c = 'removed', d = 'removed') {
|
||||
console.log(a, b, c);
|
||||
}
|
||||
|
||||
method(a = 'retained') {
|
||||
console.log(a);
|
||||
}
|
||||
|
||||
prop = (a = 'retained') => console.log(a);
|
||||
|
||||
static staticMethod(a = 'retained', b = 'retained', c = 'removed', d = 'removed') {
|
||||
console.log(a, b, c);
|
||||
}
|
||||
|
||||
static staticProp = (a = 'retained', b = 'retained', c = 'removed', d = 'removed') =>
|
||||
console.log(a, b, c);
|
||||
}
|
||||
|
||||
new Test(isUndefined, 'b', 'c');
|
||||
new Test('a', globalThis.unknown, 'c').method();
|
||||
|
||||
Test.staticMethod(isUndefined, 'b', 'c');
|
||||
Test.staticMethod('a', globalThis.unknown, 'c');
|
||||
|
||||
Test.staticProp(isUndefined, 'b', 'c');
|
||||
Test.staticProp('a', globalThis.unknown, 'c');
|
@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
description: 'handles side effects of default parameters'
|
||||
};
|
@ -1,17 +0,0 @@
|
||||
const a = (p = 'retained') => console.log(p);
|
||||
a();
|
||||
|
||||
const b = (p) => console.log(p);
|
||||
b('value');
|
||||
|
||||
const c = (p = console.log('retained because of side effect')) => {};
|
||||
c();
|
||||
|
||||
const d = (p) => console.log('effect');
|
||||
d();
|
||||
|
||||
const e = (p) => {};
|
||||
e();
|
||||
|
||||
const f = ({ x = console.log('retained') }) => {};
|
||||
f('value');
|
@ -1,17 +0,0 @@
|
||||
const a = (p = 'retained') => console.log(p);
|
||||
a();
|
||||
|
||||
const b = (p = console.log('removed')) => console.log(p);
|
||||
b('value');
|
||||
|
||||
const c = (p = console.log('retained because of side effect')) => {};
|
||||
c();
|
||||
|
||||
const d = (p = 'removed because no side effect') => console.log('effect');
|
||||
d();
|
||||
|
||||
const e = (p = console.log('removed')) => {};
|
||||
e('value');
|
||||
|
||||
const f = ({ x = console.log('retained') } = {}) => {};
|
||||
f('value');
|
@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
description: 'supports tree-shaking for unused default parameter values for functions'
|
||||
};
|
@ -1,21 +0,0 @@
|
||||
var isUndefined;
|
||||
|
||||
function funDecl(a = 'retained', b = 'retained', c, d) {
|
||||
console.log(a, b, c);
|
||||
}
|
||||
|
||||
funDecl(isUndefined, 'b', 'c');
|
||||
funDecl('a', globalThis.unknown, 'c');
|
||||
|
||||
const funExp = function (a = 'retained', b = 'retained', c, d) {
|
||||
console.log(a, b, c);
|
||||
};
|
||||
|
||||
funExp(isUndefined, 'b', 'c');
|
||||
funExp('a', globalThis.unknown, 'c');
|
||||
|
||||
const arrow = (a = 'retained', b = 'retained', c, d) =>
|
||||
console.log(a, b, c);
|
||||
|
||||
arrow(isUndefined, 'b', 'c');
|
||||
arrow('a', globalThis.unknown, 'c');
|
@ -1,21 +0,0 @@
|
||||
var isUndefined;
|
||||
|
||||
function funDecl(a = 'retained', b = 'retained', c = 'removed', d = 'removed') {
|
||||
console.log(a, b, c);
|
||||
}
|
||||
|
||||
funDecl(isUndefined, 'b', 'c');
|
||||
funDecl('a', globalThis.unknown, 'c');
|
||||
|
||||
const funExp = function (a = 'retained', b = 'retained', c = 'removed', d = 'removed') {
|
||||
console.log(a, b, c);
|
||||
};
|
||||
|
||||
funExp(isUndefined, 'b', 'c');
|
||||
funExp('a', globalThis.unknown, 'c');
|
||||
|
||||
const arrow = (a = 'retained', b = 'retained', c = 'removed', d = 'removed') =>
|
||||
console.log(a, b, c);
|
||||
|
||||
arrow(isUndefined, 'b', 'c');
|
||||
arrow('a', globalThis.unknown, 'c');
|
@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
description: 'recognizes non-literal arguments as not undefined'
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
function test(a) {
|
||||
console.log(a);
|
||||
}
|
||||
|
||||
test({});
|
||||
test([]);
|
||||
test(() => {});
|
||||
test(function () {});
|
||||
function a(){}
|
||||
test(a);
|
||||
test(Symbol);
|
@ -1,11 +0,0 @@
|
||||
function test(a = 'removed') {
|
||||
console.log(a);
|
||||
}
|
||||
|
||||
test({});
|
||||
test([]);
|
||||
test(() => {});
|
||||
test(function () {});
|
||||
function a(){}
|
||||
test(a);
|
||||
test(Symbol);
|
@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
description: 'supports tree-shaking for unused default parameter values on objects'
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
var isUndefined;
|
||||
|
||||
const test = {
|
||||
method(a = 'retained', b = 'retained', c, d) {
|
||||
console.log(a, b, c);
|
||||
}
|
||||
};
|
||||
|
||||
test.method(isUndefined, 'b', 'c');
|
||||
test.method('a', globalThis.unknown, 'c');
|
@ -1,10 +0,0 @@
|
||||
var isUndefined;
|
||||
|
||||
const test = {
|
||||
method(a = 'retained', b = 'retained', c = 'removed', d = 'removed') {
|
||||
console.log(a, b, c);
|
||||
}
|
||||
};
|
||||
|
||||
test.method(isUndefined, 'b', 'c');
|
||||
test.method('a', globalThis.unknown, 'c');
|
@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
description: 'supports tree-shaking for unused default parameter values on super classes'
|
||||
};
|
@ -1,25 +0,0 @@
|
||||
var isUndefined;
|
||||
|
||||
class TestSuper {
|
||||
constructor(a = 'retained', b = 'retained', c, d) {
|
||||
console.log(a, b, c);
|
||||
}
|
||||
|
||||
static staticMethod(a = 'retained', b = 'retained', c, d) {
|
||||
console.log(a, b, c);
|
||||
}
|
||||
|
||||
static staticProp = (a = 'retained', b = 'retained', c, d) =>
|
||||
console.log(a, b, c);
|
||||
}
|
||||
|
||||
class Test extends TestSuper {}
|
||||
|
||||
new Test(isUndefined, 'b', 'c');
|
||||
new Test('a', globalThis.unknown, 'c').method();
|
||||
|
||||
Test.staticMethod(isUndefined, 'b', 'c');
|
||||
Test.staticMethod('a', globalThis.unknown, 'c');
|
||||
|
||||
Test.staticProp(isUndefined, 'b', 'c');
|
||||
Test.staticProp('a', globalThis.unknown, 'c');
|
@ -1,25 +0,0 @@
|
||||
var isUndefined;
|
||||
|
||||
class TestSuper {
|
||||
constructor(a = 'retained', b = 'retained', c = 'removed', d = 'removed') {
|
||||
console.log(a, b, c);
|
||||
}
|
||||
|
||||
static staticMethod(a = 'retained', b = 'retained', c = 'removed', d = 'removed') {
|
||||
console.log(a, b, c);
|
||||
}
|
||||
|
||||
static staticProp = (a = 'retained', b = 'retained', c = 'removed', d = 'removed') =>
|
||||
console.log(a, b, c);
|
||||
}
|
||||
|
||||
class Test extends TestSuper {}
|
||||
|
||||
new Test(isUndefined, 'b', 'c');
|
||||
new Test('a', globalThis.unknown, 'c').method();
|
||||
|
||||
Test.staticMethod(isUndefined, 'b', 'c');
|
||||
Test.staticMethod('a', globalThis.unknown, 'c');
|
||||
|
||||
Test.staticProp(isUndefined, 'b', 'c');
|
||||
Test.staticProp('a', globalThis.unknown, 'c');
|
@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
description: 'supports tree-shaking for unused default parameter values on template tags'
|
||||
};
|
@ -1,6 +0,0 @@
|
||||
const templateTag = (_, a = 'retained', b = 'retained', c, d) => {
|
||||
console.log(a, b, c);
|
||||
};
|
||||
|
||||
templateTag`${isUndefined}${'b'}${'c'}`;
|
||||
templateTag`${'a'}${globalThis.unknown}${'c'}`;
|
@ -1,6 +0,0 @@
|
||||
const templateTag = (_, a = 'retained', b = 'retained', c = 'removed', d = 'removed') => {
|
||||
console.log(a, b, c);
|
||||
};
|
||||
|
||||
templateTag`${isUndefined}${'b'}${'c'}`;
|
||||
templateTag`${'a'}${globalThis.unknown}${'c'}`;
|
@ -1,11 +1,11 @@
|
||||
function test(a, b, c) {}
|
||||
test();
|
||||
function test(a, b = globalThis.unknown(), c) {}
|
||||
test(1, 2);
|
||||
|
||||
function noEffect() {}
|
||||
test(1, 2, noEffect(), globalThis.unknown());
|
||||
|
||||
const testArr = (a, b, c) => {};
|
||||
testArr();
|
||||
const testArr = (a, b = globalThis.unknown(), c) => {};
|
||||
testArr(1, 2);
|
||||
|
||||
function noEffectArr() {}
|
||||
testArr(1, 2, noEffectArr(), globalThis.unknown());
|
||||
|
@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
description: 'tracks mutations of class methods'
|
||||
};
|
@ -1,14 +0,0 @@
|
||||
let effect = false;
|
||||
|
||||
class Foo {
|
||||
method() {}
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
Object.defineProperty(foo.method, 'effect', {
|
||||
get() {
|
||||
effect = true;
|
||||
}
|
||||
});
|
||||
|
||||
Foo.prototype.method.effect;
|
@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
description: 'includes necessary default parameters for tagged template literals'
|
||||
};
|
@ -1,6 +0,0 @@
|
||||
const templateTag = ([, a = 'quasiFallback'], b = 'expressionFallback') => {
|
||||
assert.strictEqual(a, 'quasiFallback');
|
||||
assert.strictEqual(b, 'expressionFallback');
|
||||
};
|
||||
|
||||
templateTag``;
|
@ -1,10 +0,0 @@
|
||||
const assert = require('assert');
|
||||
|
||||
module.exports = {
|
||||
description: 'includes default parameters for exported functions',
|
||||
exports({ funDecl, funExp, arrow }) {
|
||||
assert.strictEqual(funDecl(), 'defaultValue', 'function declaration');
|
||||
assert.strictEqual(funExp(), 'defaultValue', 'function expression');
|
||||
assert.strictEqual(arrow(), 'defaultValue', 'arrow function');
|
||||
}
|
||||
};
|
@ -1,9 +0,0 @@
|
||||
export function funDecl(a = 'defaultValue') {
|
||||
return a;
|
||||
}
|
||||
|
||||
export const funExp = function (a = 'defaultValue') {
|
||||
return a;
|
||||
};
|
||||
|
||||
export const arrow = (a = 'defaultValue') => a;
|
@ -1,9 +0,0 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
description:
|
||||
'does not tree-shake necessary parameter defaults when modulesSideEffects are disabled',
|
||||
options: {
|
||||
treeshake: { moduleSideEffects: false }
|
||||
}
|
||||
};
|
@ -1,3 +0,0 @@
|
||||
import { foo } from './other';
|
||||
|
||||
assert.strictEqual(foo(), 'fallback');
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue