From a4620bd4bffdb0a4efa073b590065f9372fcaf70 Mon Sep 17 00:00:00 2001 From: Caleb Meredith Date: Tue, 18 Sep 2018 05:23:47 -0700 Subject: [PATCH] Support constructor returning an unknown abstract value (#2535) Summary: The following test case currently fails: ```js function F() { this.a = 1; this.b = 2; if (global.__abstract) return global.__abstract(undefined, "undefined"); } const result = new F(); global.inspect = () => JSON.stringify(result); ``` We hit this bug in our internal React Native bundle. I only added support for `base` construction kinds since the template for `derived` construction kinds would get more complicated. Pull Request resolved: https://github.com/facebook/prepack/pull/2535 Differential Revision: D9906309 Pulled By: trueadm fbshipit-source-id: 49a71ceaf30a851075879295e63e98ce7e1bbe2d --- src/methods/function.js | 31 ++++++++++++++----- .../ConstructFunctionReturnsAbstract.js | 9 ++++++ 2 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 test/serializer/abstract/ConstructFunctionReturnsAbstract.js diff --git a/src/methods/function.js b/src/methods/function.js index fbddaae6b..5fd8e3ca4 100644 --- a/src/methods/function.js +++ b/src/methods/function.js @@ -276,17 +276,32 @@ function InternalConstruct( function map(value: Value) { if (value === realm.intrinsics.__bottomValue) return value; - if (value instanceof AbstractValue && value.kind === "conditional") { - const [condition, consequent, alternate] = value.args; - return realm.evaluateWithAbstractConditional( - condition, - () => realm.evaluateForEffects(() => map(consequent), undefined, "AbstractValue/conditional/true"), - () => realm.evaluateForEffects(() => map(alternate), undefined, "AbstractValue/conditional/false") - ); + if (value instanceof AbstractValue) { + if (value.kind === "conditional") { + const [condition, consequent, alternate] = value.args; + return realm.evaluateWithAbstractConditional( + condition, + () => realm.evaluateForEffects(() => map(consequent), undefined, "AbstractValue/conditional/true"), + () => realm.evaluateForEffects(() => map(alternate), undefined, "AbstractValue/conditional/false") + ); + } + if (!(value instanceof AbstractObjectValue)) { + if (kind === "base") { + invariant(thisArgument, "this wasn't initialized for some reason"); + return AbstractValue.createFromTemplate( + realm, + "typeof A === 'object' || typeof A === 'function' ? A : B", + ObjectValue, + [value, thisArgument] + ); + } else { + value.throwIfNotConcreteObject(); // Not yet supported. + } + } } // a. If Type(result.[[Value]]) is Object, return NormalCompletion(result.[[Value]]). - if (value.mightBeObject()) return value.throwIfNotConcreteObject(); + if (value instanceof ObjectValue || value instanceof AbstractObjectValue) return value; // b. If kind is "base", return NormalCompletion(thisArgument). if (kind === "base") { diff --git a/test/serializer/abstract/ConstructFunctionReturnsAbstract.js b/test/serializer/abstract/ConstructFunctionReturnsAbstract.js new file mode 100644 index 000000000..9a3e5e7b9 --- /dev/null +++ b/test/serializer/abstract/ConstructFunctionReturnsAbstract.js @@ -0,0 +1,9 @@ +function F() { + this.a = 1; + this.b = 2; + if (global.__abstract) return global.__abstract(undefined, "undefined"); +} + +const result = new F(); + +global.inspect = () => JSON.stringify(result);