Support string with abstract argument (#2310)

Summary:
I was seeing `throwIfNotConcrete` a lot for `String()` calls on abstract values in #2297. The fix is relatively quick.
Pull Request resolved: https://github.com/facebook/prepack/pull/2310

Differential Revision: D8960761

Pulled By: calebmer

fbshipit-source-id: f378092cb3e36ac4026404a9e185abe9a768f577
This commit is contained in:
Caleb Meredith 2018-07-23 16:59:38 -07:00 committed by Facebook Github Bot
parent 2735f970a9
commit d3e62037aa
3 changed files with 17 additions and 20 deletions

View File

@ -10,7 +10,7 @@
/* @flow strict-local */
import type { Realm } from "../../realm.js";
import { NativeFunctionValue, NumberValue, StringValue, SymbolValue } from "../../values/index.js";
import { NativeFunctionValue, NumberValue, StringValue, SymbolValue, Value } from "../../values/index.js";
import { Get, GetPrototypeFromConstructor, SymbolDescriptiveString } from "../../methods/index.js";
import { Create, To } from "../../singletons.js";
import invariant from "../../invariant.js";
@ -18,7 +18,7 @@ import invariant from "../../invariant.js";
export default function(realm: Realm): NativeFunctionValue {
// ECMA262 21.1.1
let func = new NativeFunctionValue(realm, "String", "String", 1, (context, [value], argCount, NewTarget) => {
let s: ?StringValue;
let s: ?Value;
// 1. If no arguments were passed to this function invocation, let s be "".
if (argCount === 0) {
@ -31,13 +31,14 @@ export default function(realm: Realm): NativeFunctionValue {
}
// b. Let s be ? ToString(value).
s = new StringValue(realm, To.ToStringPartial(realm, value));
s = To.ToStringValue(realm, value);
}
// 3. If NewTarget is undefined, return s.
if (!NewTarget) return s;
// 4. Return ? StringCreate(s, ? GetPrototypeFromConstructor(NewTarget, "%StringPrototype%")).
s = s.throwIfNotConcreteString();
return Create.StringCreate(realm, s, GetPrototypeFromConstructor(realm, NewTarget, "StringPrototype"));
});

View File

@ -719,29 +719,18 @@ export class ToImplementation {
ToStringValue(realm: Realm, val: Value): Value {
if (val.getType() === StringValue) return val;
let str;
if (typeof val === "string") {
str = val;
} else if (val instanceof NumberValue) {
str = val.value + "";
} else if (val instanceof UndefinedValue) {
str = "undefined";
} else if (val instanceof NullValue) {
str = "null";
} else if (val instanceof SymbolValue) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
} else if (val instanceof BooleanValue) {
str = val.value ? "true" : "false";
} else if (val instanceof ObjectValue) {
if (val instanceof ObjectValue) {
let primValue = this.ToPrimitiveOrAbstract(realm, val, "string");
if (primValue.getType() === StringValue) return primValue;
str = this.ToStringPartial(realm, primValue);
return this.ToStringValue(realm, primValue);
} else if (val instanceof ConcreteValue) {
let str = this.ToString(realm, val);
return new StringValue(realm, str);
} else if (val instanceof AbstractValue) {
return this.ToStringAbstract(realm, val);
} else {
invariant(false, "unknown value type, can't coerce to string");
}
return new StringValue(realm, str);
}
ToStringAbstract(realm: Realm, value: AbstractValue): AbstractValue {
@ -749,7 +738,7 @@ export class ToImplementation {
let result;
// If the property is not a string we need to coerce it.
let coerceToString = createOperationDescriptor("COERCE_TO_STRING");
if (value.mightNotBeNumber() && !value.isSimpleObject()) {
if (value.mightBeObject() && !value.isSimpleObject()) {
// If this might be a non-simple object, we need to coerce this at a
// temporal point since it can have side-effects.
// We can't rely on comparison to do it later, even if

View File

@ -0,0 +1,7 @@
var a = String(global.__abstract ? __abstract("string", '"foo"') : "foo");
var b = String(global.__abstract ? __abstract("number", "42") : 42);
var c = String(global.__abstract ? __abstract("boolean", "true") : true);
inspect = function() {
return JSON.stringify({ a, b, c });
};