mirror of
https://github.com/facebookarchive/prepack.git
synced 2024-09-20 03:27:09 +03:00
Handle PossiblyNormal completions inside try
Summary: If the try block of a try-catch statement possibly throws an exception, bring the effects of the catch handler into the state of the exceptional control flow and carry on. Closes https://github.com/facebook/prepack/pull/1046 Differential Revision: D5989477 Pulled By: hermanventer fbshipit-source-id: 37dcd36e817d642122602554f71e0ba19706c400
This commit is contained in:
parent
237d9bd5ab
commit
076d234acb
@ -11,22 +11,56 @@
|
|||||||
|
|
||||||
import type { Realm } from "../realm.js";
|
import type { Realm } from "../realm.js";
|
||||||
import type { LexicalEnvironment } from "../environment.js";
|
import type { LexicalEnvironment } from "../environment.js";
|
||||||
import { AbruptCompletion, ThrowCompletion } from "../completions.js";
|
import { AbruptCompletion, Completion, PossiblyNormalCompletion, ThrowCompletion } from "../completions.js";
|
||||||
import { UpdateEmpty } from "../methods/index.js";
|
import { joinEffects, UpdateEmpty } from "../methods/index.js";
|
||||||
import { Value } from "../values/index.js";
|
import { Value } from "../values/index.js";
|
||||||
import type { BabelNodeTryStatement } from "babel-types";
|
import type { BabelNodeTryStatement } from "babel-types";
|
||||||
import invariant from "../invariant.js";
|
import invariant from "../invariant.js";
|
||||||
|
|
||||||
export default function(ast: BabelNodeTryStatement, strictCode: boolean, env: LexicalEnvironment, realm: Realm): Value {
|
export default function(
|
||||||
|
ast: BabelNodeTryStatement,
|
||||||
|
strictCode: boolean,
|
||||||
|
env: LexicalEnvironment,
|
||||||
|
realm: Realm
|
||||||
|
): PossiblyNormalCompletion | Value {
|
||||||
let completions = [];
|
let completions = [];
|
||||||
|
|
||||||
let blockRes = env.evaluateCompletion(ast.block, strictCode);
|
let blockRes = env.evaluateAbstractCompletion(ast.block, strictCode);
|
||||||
|
if (blockRes instanceof PossiblyNormalCompletion) {
|
||||||
|
let abruptCompletion;
|
||||||
|
let abruptEffects;
|
||||||
|
if (blockRes.consequent instanceof AbruptCompletion) {
|
||||||
|
abruptCompletion = blockRes.consequent;
|
||||||
|
abruptEffects = blockRes.consequentEffects;
|
||||||
|
} else {
|
||||||
|
abruptCompletion = blockRes.alternate;
|
||||||
|
abruptEffects = blockRes.alternateEffects;
|
||||||
|
}
|
||||||
|
if (abruptCompletion instanceof ThrowCompletion && ast.handler) {
|
||||||
|
let normalEffects = realm.getCapturedEffects(blockRes.value);
|
||||||
|
invariant(normalEffects !== undefined);
|
||||||
|
realm.stopEffectCaptureAndUndoEffects();
|
||||||
|
let handlerEffects = realm.evaluateForEffects(() => {
|
||||||
|
realm.applyEffects(abruptEffects);
|
||||||
|
invariant(ast.handler);
|
||||||
|
return env.evaluateAbstractCompletion(ast.handler, strictCode, abruptCompletion);
|
||||||
|
});
|
||||||
|
let jointEffects;
|
||||||
|
if (blockRes.consequent instanceof AbruptCompletion)
|
||||||
|
jointEffects = joinEffects(realm, blockRes.joinCondition, handlerEffects, normalEffects);
|
||||||
|
else jointEffects = joinEffects(realm, blockRes.joinCondition, normalEffects, handlerEffects);
|
||||||
|
realm.applyEffects(jointEffects);
|
||||||
|
completions.unshift(jointEffects[0]);
|
||||||
|
} else {
|
||||||
|
completions.unshift(blockRes);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (blockRes instanceof ThrowCompletion && ast.handler) {
|
if (blockRes instanceof ThrowCompletion && ast.handler) {
|
||||||
completions.unshift(env.evaluateCompletion(ast.handler, strictCode, blockRes));
|
completions.unshift(env.evaluateCompletion(ast.handler, strictCode, blockRes));
|
||||||
} else {
|
} else {
|
||||||
completions.unshift(blockRes);
|
completions.unshift(blockRes);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ast.finalizer) {
|
if (ast.finalizer) {
|
||||||
completions.unshift(env.evaluateCompletion(ast.finalizer, strictCode));
|
completions.unshift(env.evaluateCompletion(ast.finalizer, strictCode));
|
||||||
@ -34,7 +68,7 @@ export default function(ast: BabelNodeTryStatement, strictCode: boolean, env: Le
|
|||||||
|
|
||||||
// use the last completion record
|
// use the last completion record
|
||||||
for (let completion of completions) {
|
for (let completion of completions) {
|
||||||
if (completion && completion instanceof AbruptCompletion) throw completion;
|
if (completion instanceof AbruptCompletion) throw completion;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ast.finalizer) {
|
if (ast.finalizer) {
|
||||||
@ -43,7 +77,7 @@ export default function(ast: BabelNodeTryStatement, strictCode: boolean, env: Le
|
|||||||
|
|
||||||
// otherwise use the last returned value
|
// otherwise use the last returned value
|
||||||
for (let completion of completions) {
|
for (let completion of completions) {
|
||||||
if (completion && completion instanceof Value)
|
if (completion instanceof Value || completion instanceof Completion)
|
||||||
return (UpdateEmpty(realm, completion, realm.intrinsics.undefined): any);
|
return (UpdateEmpty(realm, completion, realm.intrinsics.undefined): any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
// throws introspection error
|
|
||||||
let x = global.__abstract ? __abstract("boolean", "true") : true;
|
let x = global.__abstract ? __abstract("boolean", "true") : true;
|
||||||
let y;
|
let y;
|
||||||
try {
|
try {
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
// throws introspection error
|
let x = global.__abstract ? __abstract("boolean", "true") : true;
|
||||||
|
|
||||||
let x = __abstract("boolean", "true");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (x) throw new Error("is true");
|
if (x) throw new Error("is true");
|
||||||
@ -8,3 +6,5 @@ try {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
z = e;
|
z = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inspect = function() { return z; }
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// throws introspection error
|
let x = global.__abstract ? __abstract("boolean", "true") : true;
|
||||||
|
|
||||||
let x = __abstract("boolean", "true");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (x) z = "is true"; else throw "is false";
|
if (x) z = "is true"; else throw "is false";
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
z = e;
|
z = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inspect = function() { return z; }
|
||||||
|
11
test/serializer/abstract/Throw4.js
Normal file
11
test/serializer/abstract/Throw4.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// throws introspection error
|
||||||
|
|
||||||
|
let x = global.__abstract ? __abstract("boolean", "true") : true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (x) z = "is true"; else throw "is false";
|
||||||
|
} finally {
|
||||||
|
z = "is finally";
|
||||||
|
}
|
||||||
|
|
||||||
|
inspect = function() { return z; }
|
Loading…
Reference in New Issue
Block a user