Make constant folding more powerful

Reviewed By: davidaurelio

Differential Revision: D8038008

fbshipit-source-id: 06c81ccf4e816ceefeb6673f247fd0bac41429a6
This commit is contained in:
Miguel Jimenez Esun 2018-05-21 07:52:20 -07:00 committed by Facebook Github Bot
parent 54828cce35
commit 4a75826683
5 changed files with 88 additions and 68 deletions

View File

@ -20,6 +20,7 @@
"@babel/plugin-proposal-class-properties": "7.0.0-beta.40",
"@babel/plugin-proposal-object-rest-spread": "7.0.0-beta.40",
"@babel/plugin-syntax-dynamic-import": "7.0.0-beta.40",
"@babel/plugin-syntax-nullish-coalescing-operator": "7.0.0-beta.40",
"@babel/plugin-transform-arrow-functions": "7.0.0-beta.40",
"@babel/plugin-transform-async-to-generator": "7.0.0-beta.40",
"@babel/plugin-transform-block-scoping": "7.0.0-beta.40",

View File

@ -38,6 +38,7 @@ function parse(code: string): TransformResult {
code: false,
babelrc: false,
compact: true,
plugins: [require('@babel/plugin-syntax-nullish-coalescing-operator')],
sourceMaps: true,
});
}
@ -107,6 +108,20 @@ describe('constant expressions', () => {
);
});
it('folds null coalescing operator', () => {
const code = `
var a = undefined ?? u();
var b = null ?? v();
var c = false ?? w();
var d = 0 ?? x();
var e = NaN ?? x();
var f = "truthy" ?? z();
`;
expect(fold('arbitrary.js', code)).toEqual(
'var a=u();var b=v();var c=false;var d=0;var e=NaN;var f="truthy";',
);
});
it('can remode an if statement with a falsy constant test', () => {
const code = `
if ('production' === 'development' || false) {
@ -149,4 +164,26 @@ describe('constant expressions', () => {
`;
expect(fold('arbitrary.js', code)).toEqual("{{require('c');}}");
});
it('folds if expressions with variables', () => {
const code = `
var x = 3;
if (x - 3) {
require('a');
}
`;
expect(fold('arbitrary.js', code)).toEqual('var x=3;');
});
it('folds logical expressions with variables', () => {
const code = `
var x = 3;
var y = (x - 3) || 4;
var z = (y - 4) && 4;
`;
expect(fold('arbitrary.js', code)).toEqual('var x=3;var y=4;var z=0;');
});
});

View File

@ -18,54 +18,60 @@ function constantFoldingPlugin(context: {types: BabelTypes}) {
const Conditional = {
exit(path: Object) {
const node = path.node;
const test = node.test;
if (t.isLiteral(test)) {
if (test.value || node.alternate) {
path.replaceWith(test.value ? node.consequent : node.alternate);
} else if (!test.value) {
const result = path.get('test').evaluate();
if (result.confident) {
if (result.value || node.alternate) {
path.replaceWith(result.value ? node.consequent : node.alternate);
} else if (!result.value) {
path.remove();
}
}
},
};
const Expression = {
exit(path: Object) {
const result = path.evaluate();
if (result.confident) {
path.replaceWith(t.valueToNode(result.value));
}
},
};
const LogicalExpression = {
exit(path: Object) {
const node = path.node;
const result = path.get('left').evaluate();
if (result.confident) {
const value = result.value;
switch (node.operator) {
case '||':
path.replaceWith(value ? node.left : node.right);
break;
case '&&':
path.replaceWith(value ? node.right : node.left);
break;
case '??':
path.replaceWith(value == null ? node.right : node.left);
break;
}
}
},
};
return {
visitor: {
BinaryExpression: {
exit(path: Object) {
const node = path.node;
if (t.isLiteral(node.left) && t.isLiteral(node.right)) {
const result = path.evaluate();
if (result.confident) {
path.replaceWith(t.valueToNode(result.value));
}
}
},
},
BinaryExpression: Expression,
ConditionalExpression: Conditional,
IfStatement: Conditional,
LogicalExpression: {
exit(path: Object) {
const node = path.node;
const left = node.left;
if (t.isLiteral(left)) {
const value = t.isNullLiteral(left) ? null : left.value;
if (node.operator === '||') {
path.replaceWith(value ? left : node.right);
} else {
path.replaceWith(value ? node.right : left);
}
}
},
},
UnaryExpression: {
exit(path: Object) {
const node = path.node;
if (node.operator === '!' && t.isLiteral(node.argument)) {
path.replaceWith(t.valueToNode(!node.argument.value));
}
},
},
LogicalExpression,
UnaryExpression: Expression,
},
};
}

View File

@ -22,16 +22,6 @@ exports[`basic_bundle bundles package with polyfills 1`] = `
hasError: false,
isInitialized: false
};
if (PRINT_REQUIRE_PATHS) {
var _path = arguments[4];
if (_path) {
modules[moduleId].path = _path;
} else {
throw new Error(\\"path not set on module with PRINT_REQUIRE_PATHS true. Make sure PASS_MODULE_PATHS_TO_DEFINE is true and restart Metro or rebuild bundle\\");
}
}
}
function metroRequire(moduleId) {
@ -61,7 +51,7 @@ exports[`basic_bundle bundles package with polyfills 1`] = `
}
var ID_MASK_SHIFT = 16;
var LOCAL_ID_MASK = ~0 >>> ID_MASK_SHIFT;
var LOCAL_ID_MASK = 65535;
function unpackModuleId(moduleId) {
var segmentId = moduleId >>> ID_MASK_SHIFT;
@ -107,10 +97,6 @@ exports[`basic_bundle bundles package with polyfills 1`] = `
dependencyMap = _module.dependencyMap;
try {
if (PRINT_REQUIRE_PATHS) {
console.log(\\"require file path \\" + (module.path || 'unknown'));
}
var _moduleObject = {
exports: exports
};
@ -225,16 +211,6 @@ exports[`basic_bundle bundles package without polyfills 1`] = `
hasError: false,
isInitialized: false
};
if (PRINT_REQUIRE_PATHS) {
var _path = arguments[4];
if (_path) {
modules[moduleId].path = _path;
} else {
throw new Error(\\"path not set on module with PRINT_REQUIRE_PATHS true. Make sure PASS_MODULE_PATHS_TO_DEFINE is true and restart Metro or rebuild bundle\\");
}
}
}
function metroRequire(moduleId) {
@ -264,7 +240,7 @@ exports[`basic_bundle bundles package without polyfills 1`] = `
}
var ID_MASK_SHIFT = 16;
var LOCAL_ID_MASK = ~0 >>> ID_MASK_SHIFT;
var LOCAL_ID_MASK = 65535;
function unpackModuleId(moduleId) {
var segmentId = moduleId >>> ID_MASK_SHIFT;
@ -310,10 +286,6 @@ exports[`basic_bundle bundles package without polyfills 1`] = `
dependencyMap = _module.dependencyMap;
try {
if (PRINT_REQUIRE_PATHS) {
console.log(\\"require file path \\" + (module.path || 'unknown'));
}
var _moduleObject = {
exports: exports
};

View File

@ -250,6 +250,10 @@
version "7.0.0-beta.40"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.0.0-beta.40.tgz#db44d52ff06f784be22f2659e694cc2cf97f99f9"
"@babel/plugin-syntax-nullish-coalescing-operator@7.0.0-beta.40":
version "7.0.0-beta.40"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.0.0-beta.40.tgz#1bd13137a2053b1bab0bb4e914e141fd67a10d7e"
"@babel/plugin-syntax-object-rest-spread@7.0.0-beta.40":
version "7.0.0-beta.40"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0-beta.40.tgz#d5e04536062e4df685c203ae48bb19bfe2cf235c"