From 893e2556d3ad11e229da793a00227ec4ce022a84 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Mon, 23 Jun 2014 10:56:51 -0500 Subject: [PATCH] Bug 645416, part 17 - Implement ToPrimitive on Symbol wrapper objects. r=sfink. The spec defines this by way of a @@toPrimitive method. We fake it using a JSClass::convert hook. (Once @@toPrimitive is implemented, convert hooks can be removed entirely, but we need symbols first.) --HG-- extra : rebase_source : c8c7ed3eead8bd79bb38b70f448ebb98c5b3d780 --- js/src/builtin/SymbolObject.cpp | 10 +++++++++- js/src/builtin/SymbolObject.h | 2 ++ js/src/js.msg | 2 +- js/src/tests/ecma_6/Symbol/constructor.js | 2 ++ js/src/tests/ecma_6/Symbol/conversions.js | 18 ++++++++++++++++++ 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/js/src/builtin/SymbolObject.cpp b/js/src/builtin/SymbolObject.cpp index d2dc7969d54..46c11aa9d06 100644 --- a/js/src/builtin/SymbolObject.cpp +++ b/js/src/builtin/SymbolObject.cpp @@ -24,7 +24,7 @@ const Class SymbolObject::class_ = { JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, JS_ResolveStub, - JS_ConvertStub + convert }; SymbolObject * @@ -121,6 +121,14 @@ SymbolObject::construct(JSContext *cx, unsigned argc, Value *vp) return true; } +// Stand-in for Symbol.prototype[@@toPrimitive], ES6 rev 25 (2014 May 22) 19.4.3.4 +bool +SymbolObject::convert(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_SYMBOL_TO_PRIMITIVE); + return false; +} + // ES6 rev 24 (2014 Apr 27) 19.4.2.2 bool SymbolObject::for_(JSContext *cx, unsigned argc, Value *vp) diff --git a/js/src/builtin/SymbolObject.h b/js/src/builtin/SymbolObject.h index 66f16a3b4c7..d8ae7c99bf9 100644 --- a/js/src/builtin/SymbolObject.h +++ b/js/src/builtin/SymbolObject.h @@ -42,6 +42,8 @@ class SymbolObject : public JSObject static bool construct(JSContext *cx, unsigned argc, Value *vp); + static bool convert(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp); + // Static methods. static bool for_(JSContext *cx, unsigned argc, Value *vp); diff --git a/js/src/js.msg b/js/src/js.msg index a383543a3c9..3ebe178d5a5 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -239,7 +239,7 @@ MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 185, 0, JSEXN_TYPEERR, "proxy can't MSG_DEF(JSMSG_SYMBOL_TO_STRING, 186, 0, JSEXN_TYPEERR, "can't convert symbol to string") MSG_DEF(JSMSG_UNUSED187, 187, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 188, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}") -MSG_DEF(JSMSG_UNUSED189, 189, 0, JSEXN_NONE, "") +MSG_DEF(JSMSG_SYMBOL_TO_PRIMITIVE, 189, 0, JSEXN_TYPEERR, "can't convert symbol object to primitive") MSG_DEF(JSMSG_UNUSED190, 190, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_BAD_INDEX, 191, 0, JSEXN_RANGEERR, "invalid or out-of-range index") MSG_DEF(JSMSG_UNUSED192, 192, 0, JSEXN_NONE, "") diff --git a/js/src/tests/ecma_6/Symbol/constructor.js b/js/src/tests/ecma_6/Symbol/constructor.js index 0732de16393..5143b02a9e4 100644 --- a/js/src/tests/ecma_6/Symbol/constructor.js +++ b/js/src/tests/ecma_6/Symbol/constructor.js @@ -13,6 +13,8 @@ assertEq(Symbol(7).toString(), "Symbol(7)"); assertEq(Symbol(true).toString(), "Symbol(true)"); assertEq(Symbol(null).toString(), "Symbol(null)"); assertEq(Symbol([1, 2]).toString(), "Symbol(1,2)"); +var symobj = Object(sym); +assertThrowsInstanceOf(() => Symbol(symobj), TypeError); var hits = 0; var obj = { diff --git a/js/src/tests/ecma_6/Symbol/conversions.js b/js/src/tests/ecma_6/Symbol/conversions.js index 66fe86dca2e..a97cb3cfbd4 100644 --- a/js/src/tests/ecma_6/Symbol/conversions.js +++ b/js/src/tests/ecma_6/Symbol/conversions.js @@ -7,7 +7,25 @@ var symbols = [ Symbol.iterator ]; +if (Symbol.toPrimitive in Symbol.prototype) { + // We should test that deleting Symbol.prototype[@@toPrimitive] changes the + // behavior of ToPrimitive on Symbol objects, but @@toPrimitive is not + // implemented yet. + throw new Error("Congratulations on implementing @@toPrimitive! Please update this test."); +} + for (var sym of symbols) { + // 7.1.1 ToPrimitive + var symobj = Object(sym); + assertThrowsInstanceOf(() => Number(symobj), TypeError); + assertThrowsInstanceOf(() => String(symobj), TypeError); + assertThrowsInstanceOf(() => symobj < 0, TypeError); + assertThrowsInstanceOf(() => 0 < symobj, TypeError); + assertThrowsInstanceOf(() => symobj == 0, TypeError); + assertThrowsInstanceOf(() => 0 != symobj, TypeError); + assertThrowsInstanceOf(() => symobj + 1, TypeError); + assertThrowsInstanceOf(() => "" + symobj, TypeError); + // 7.1.2 ToBoolean assertEq(Boolean(sym), true); assertEq(!sym, false);