Forward deopt node path in NodePath#evaludate (#11832)

* Forward deopt node path

* Move deopt evaluation tests

* Document evaluate deopt property
This commit is contained in:
Johan Holmerin 2020-08-20 22:20:19 +02:00 committed by GitHub
parent bd07cda4a5
commit b9407d7660
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 8 deletions

View File

@ -219,7 +219,7 @@ function _evaluate(path, state) {
if (elemValue.confident) { if (elemValue.confident) {
arr.push(elemValue.value); arr.push(elemValue.value);
} else { } else {
return deopt(elem, state); return deopt(elemValue.deopt, state);
} }
} }
return arr; return arr;
@ -237,7 +237,7 @@ function _evaluate(path, state) {
if (prop.node.computed) { if (prop.node.computed) {
key = key.evaluate(); key = key.evaluate();
if (!key.confident) { if (!key.confident) {
return deopt(keyPath, state); return deopt(key.deopt, state);
} }
key = key.value; key = key.value;
} else if (key.isIdentifier()) { } else if (key.isIdentifier()) {
@ -248,7 +248,7 @@ function _evaluate(path, state) {
const valuePath = prop.get("value"); const valuePath = prop.get("value");
let value = valuePath.evaluate(); let value = valuePath.evaluate();
if (!value.confident) { if (!value.confident) {
return deopt(valuePath, state); return deopt(value.deopt, state);
} }
value = value.value; value = value.value;
obj[key] = value; obj[key] = value;
@ -407,19 +407,24 @@ function evaluateQuasis(path, quasis: Array<Object>, state, raw = false) {
/** /**
* Walk the input `node` and statically evaluate it. * Walk the input `node` and statically evaluate it.
* *
* Returns an object in the form `{ confident, value }`. `confident` indicates * Returns an object in the form `{ confident, value, deopt }`. `confident`
* whether or not we had to drop out of evaluating the expression because of * indicates whether or not we had to drop out of evaluating the expression
* hitting an unknown node that we couldn't confidently find the value of. * because of hitting an unknown node that we couldn't confidently find the
* value of, in which case `deopt` is the path of said node.
* *
* Example: * Example:
* *
* t.evaluate(parse("5 + 5")) // { confident: true, value: 10 } * t.evaluate(parse("5 + 5")) // { confident: true, value: 10 }
* t.evaluate(parse("!true")) // { confident: true, value: false } * t.evaluate(parse("!true")) // { confident: true, value: false }
* t.evaluate(parse("foo + foo")) // { confident: false, value: undefined } * t.evaluate(parse("foo + foo")) // { confident: false, value: undefined, deopt: NodePath }
* *
*/ */
export function evaluate(): { confident: boolean, value: any } { export function evaluate(): {
confident: boolean,
value: any,
deopt?: NodePath,
} {
const state = { const state = {
confident: true, confident: true,
deoptPath: null, deoptPath: null,

View File

@ -13,6 +13,25 @@ function getPath(code) {
return path; return path;
} }
function addDeoptTest(code, type, expectedType) {
it(type + " deopt: " + code, function () {
const visitor = {};
visitor[type] = function (path) {
const evaluate = path.evaluate();
expect(evaluate.confident).toBeFalsy();
expect(evaluate.deopt.type).toEqual(expectedType);
};
traverse(
parse(code, {
plugins: ["*"],
}),
visitor,
);
});
}
describe("evaluation", function () { describe("evaluation", function () {
describe("evaluateTruthy", function () { describe("evaluateTruthy", function () {
it("it should work with null", function () { it("it should work with null", function () {
@ -228,4 +247,8 @@ describe("evaluation", function () {
expect(result.deopt).toBeNull(); expect(result.deopt).toBeNull();
expect(result.value).toEqual(["foo", "bar"]); expect(result.value).toEqual(["foo", "bar"]);
}); });
addDeoptTest("({a:{b}})", "ObjectExpression", "Identifier");
addDeoptTest("({[a + 'b']: 1})", "ObjectExpression", "Identifier");
addDeoptTest("[{a}]", "ArrayExpression", "Identifier");
}); });