From 15da675ace95e49409d9f25ac13f0a3fbddbf21f Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Thu, 12 Sep 2024 12:17:52 -0700 Subject: [PATCH] spike(pass-style)! remove passable symbols to see what breaks --- packages/exo/src/exo-tools.js | 6 +- packages/exo/test/heap-classes.test.js | 10 +- .../exo/test/non-enumerable-methods.test.js | 9 +- packages/marshal/src/encodePassable.js | 14 --- packages/marshal/src/encodeToCapData.js | 22 ---- packages/marshal/src/encodeToSmallcaps.js | 11 -- packages/marshal/src/marshal-justin.js | 29 +---- packages/marshal/src/rankOrder.js | 8 +- packages/marshal/src/types.js | 5 +- packages/marshal/test/_marshal-test-data.js | 20 --- packages/marshal/test/marshal-capdata.test.js | 4 +- .../marshal/test/marshal-smallcaps.test.js | 16 +-- .../test/fixtures/exportheavy.js | 8 -- packages/pass-style/index.js | 7 -- packages/pass-style/src/passStyleOf.js | 5 - packages/pass-style/src/symbol.js | 117 ------------------ packages/pass-style/src/types.d.ts | 6 +- packages/pass-style/src/types.test-d.ts | 1 - packages/pass-style/test/passStyleOf.test.js | 5 +- packages/pass-style/tools/arb-passable.js | 9 -- packages/patterns/src/keys/compareKeys.js | 4 - .../patterns/src/patterns/getGuardPayloads.js | 12 +- .../patterns/src/patterns/patternMatchers.js | 55 +------- packages/patterns/src/types.js | 2 - packages/patterns/test/pattern-limits.test.js | 27 ---- packages/patterns/test/patterns.test.js | 1 - 26 files changed, 17 insertions(+), 396 deletions(-) delete mode 100644 packages/pass-style/src/symbol.js diff --git a/packages/exo/src/exo-tools.js b/packages/exo/src/exo-tools.js index d228f1b7f6..d9ba28964a 100644 --- a/packages/exo/src/exo-tools.js +++ b/packages/exo/src/exo-tools.js @@ -9,7 +9,6 @@ import { getAwaitArgGuardPayload, getMethodGuardPayload, getInterfaceGuardPayload, - getCopyMapEntries, } from '@endo/patterns'; import { listDifference } from '@endo/common/list-difference.js'; import { objectMap } from '@endo/common/object-map.js'; @@ -22,7 +21,7 @@ import { GET_INTERFACE_GUARD } from './get-interface.js'; */ const { apply, ownKeys } = Reflect; -const { defineProperties, fromEntries } = Object; +const { defineProperties } = Object; /** * A method guard, for inclusion in an interface guard, that does not @@ -381,14 +380,11 @@ export const defendPrototype = ( const { interfaceName, methodGuards: mg, - symbolMethodGuards, sloppy, defaultGuards: dg = sloppy ? 'passable' : defaultGuards, } = getInterfaceGuardPayload(interfaceGuard); methodGuards = harden({ ...mg, - ...(symbolMethodGuards && - fromEntries(getCopyMapEntries(symbolMethodGuards))), }); defaultGuards = dg; { diff --git a/packages/exo/test/heap-classes.test.js b/packages/exo/test/heap-classes.test.js index d41352e986..c6280f9ad4 100644 --- a/packages/exo/test/heap-classes.test.js +++ b/packages/exo/test/heap-classes.test.js @@ -81,23 +81,15 @@ test('test defineExoClass', t => { t.deepEqual(upCounter[GET_INTERFACE_GUARD]?.(), UpCounterI); t.deepEqual(getInterfaceMethodKeys(UpCounterI), ['incr']); - const symbolic = Symbol.for('symbolic'); const FooI = M.interface('Foo', { m: M.call().returns(), - [symbolic]: M.call(M.boolean()).returns(), }); - t.deepEqual(getInterfaceMethodKeys(FooI), ['m', Symbol.for('symbolic')]); + t.deepEqual(getInterfaceMethodKeys(FooI), ['m']); const makeFoo = defineExoClass('Foo', FooI, () => ({}), { m() {}, - [symbolic]() {}, }); const foo = makeFoo(); t.deepEqual(foo[GET_INTERFACE_GUARD]?.(), FooI); - // @ts-expect-error intentional for test - t.throws(() => foo[symbolic]('invalid arg'), { - message: - 'In "[Symbol(symbolic)]" method of (Foo): arg 0: string "invalid arg" - Must be a boolean', - }); }); test('test defineExoClassKit', t => { diff --git a/packages/exo/test/non-enumerable-methods.test.js b/packages/exo/test/non-enumerable-methods.test.js index fb51812c43..02816ef063 100644 --- a/packages/exo/test/non-enumerable-methods.test.js +++ b/packages/exo/test/non-enumerable-methods.test.js @@ -49,25 +49,18 @@ test('test defineExoClass', t => { t.deepEqual(upCounter[GET_INTERFACE_GUARD](), UpCounterI); t.deepEqual(getInterfaceMethodKeys(UpCounterI), ['incr']); - const symbolic = Symbol.for('symbolic'); const FooI = M.interface('Foo', { m: M.call().returns(), - [symbolic]: M.call(M.boolean()).returns(), }); - t.deepEqual(getInterfaceMethodKeys(FooI), ['m', Symbol.for('symbolic')]); + t.deepEqual(getInterfaceMethodKeys(FooI), ['m']); const makeFoo = defineExoClass( 'Foo', FooI, () => ({}), denumerate({ m() {}, - [symbolic]() {}, }), ); const foo = makeFoo(); t.deepEqual(foo[GET_INTERFACE_GUARD](), FooI); - t.throws(() => foo[symbolic]('invalid arg'), { - message: - 'In "[Symbol(symbolic)]" method of (Foo): arg 0: string "invalid arg" - Must be a boolean', - }); }); diff --git a/packages/marshal/src/encodePassable.js b/packages/marshal/src/encodePassable.js index 0935900749..000b0de0be 100644 --- a/packages/marshal/src/encodePassable.js +++ b/packages/marshal/src/encodePassable.js @@ -5,8 +5,6 @@ import { passStyleOf, assertRecord, isErrorLike, - nameForPassableSymbol, - passableSymbolForName, } from '@endo/pass-style'; /** @@ -617,12 +615,6 @@ const makeInnerEncode = (encodeStringSuffix, encodeArray, options) => { case 'promise': { return encodePromise(passable, innerEncode); } - case 'symbol': { - // Strings and symbols share encoding logic. - const name = nameForPassableSymbol(passable); - assert.typeof(name, 'string'); - return `y${encodeStringSuffix(name)}`; - } case 'copyArray': { return encodeArray(passable, innerEncode); } @@ -709,11 +701,6 @@ const makeInnerDecode = (decodeStringSuffix, decodeArray, options) => { case '!': { return decodeError(getSuffix(encoded, skip), innerDecode); } - case 'y': { - // Strings and symbols share decoding logic. - const name = decodeStringSuffix(getSuffix(encoded, skip + 1)); - return passableSymbolForName(name); - } case '[': case '^': { // @ts-expect-error Type 'unknown[]' is not Passable @@ -876,7 +863,6 @@ export const passStylePrefixes = { remotable: 'r', string: 's', null: 'v', - symbol: 'y', // Because Array.prototype.sort puts undefined values at the end without // passing them to a comparison function, undefined MUST be the last // category. diff --git a/packages/marshal/src/encodeToCapData.js b/packages/marshal/src/encodeToCapData.js index 052b5795a1..35211b40d8 100644 --- a/packages/marshal/src/encodeToCapData.js +++ b/packages/marshal/src/encodeToCapData.js @@ -13,9 +13,6 @@ import { isObject, getTag, hasOwnPropertyOf, - assertPassableSymbol, - nameForPassableSymbol, - passableSymbolForName, } from '@endo/pass-style'; import { X, Fail, q } from '@endo/errors'; @@ -155,14 +152,6 @@ export const makeEncodeToCapData = (encodeOptions = {}) => { digits: String(passable), }; } - case 'symbol': { - assertPassableSymbol(passable); - const name = /** @type {string} */ (nameForPassableSymbol(passable)); - return { - [QCLASS]: 'symbol', - name, - }; - } case 'copyRecord': { if (hasOwnPropertyOf(passable, QCLASS)) { // Hilbert hotel @@ -349,17 +338,6 @@ export const makeDecodeFromCapData = (decodeOptions = {}) => { Fail`invalid digits typeof ${q(typeof digits)}`; return BigInt(digits); } - case '@@asyncIterator': { - // Deprecated qclass. TODO make conditional - // on environment variable. Eventually remove, but after confident - // that there are no more supported senders. - // - return Symbol.asyncIterator; - } - case 'symbol': { - const { name } = jsonEncoded; - return passableSymbolForName(name); - } case 'tagged': { const { tag, payload } = jsonEncoded; return makeTagged(tag, decodeFromCapData(payload)); diff --git a/packages/marshal/src/encodeToSmallcaps.js b/packages/marshal/src/encodeToSmallcaps.js index 9122e56c79..0f548c41f9 100644 --- a/packages/marshal/src/encodeToSmallcaps.js +++ b/packages/marshal/src/encodeToSmallcaps.js @@ -13,9 +13,6 @@ import { makeTagged, getTag, hasOwnPropertyOf, - assertPassableSymbol, - nameForPassableSymbol, - passableSymbolForName, } from '@endo/pass-style'; import { X, Fail, q } from '@endo/errors'; @@ -209,11 +206,6 @@ export const makeEncodeToSmallcaps = (encodeOptions = {}) => { const str = String(passable); return /** @type {bigint} */ (passable) < 0n ? str : `+${str}`; } - case 'symbol': { - assertPassableSymbol(passable); - const name = /** @type {string} */ (nameForPassableSymbol(passable)); - return `%${name}`; - } case 'copyRecord': { // Currently copyRecord allows only string keys so this will // work. If we allow sortable symbol keys, this will need to @@ -353,9 +345,6 @@ export const makeDecodeFromSmallcaps = (decodeOptions = {}) => { // un-hilbert-ify the string return encoding.slice(1); } - case '%': { - return passableSymbolForName(encoding.slice(1)); - } case '#': { switch (encoding) { case '#undefined': { diff --git a/packages/marshal/src/marshal-justin.js b/packages/marshal/src/marshal-justin.js index 681c14e962..231e21e7ba 100644 --- a/packages/marshal/src/marshal-justin.js +++ b/packages/marshal/src/marshal-justin.js @@ -1,11 +1,7 @@ /// import { Nat } from '@endo/nat'; -import { - getErrorConstructor, - isObject, - passableSymbolForName, -} from '@endo/pass-style'; +import { getErrorConstructor, isObject } from '@endo/pass-style'; import { q, X, Fail } from '@endo/errors'; import { QCLASS } from './encodeToCapData.js'; @@ -165,13 +161,6 @@ const decodeToJustin = (encoding, shouldIndent = false, slots = []) => { case '@@asyncIterator': { return; } - case 'symbol': { - const { name } = rawTree; - assert.typeof(name, 'string'); - const sym = passableSymbolForName(name); - assert.typeof(sym, 'symbol'); - return; - } case 'tagged': { const { tag, payload } = rawTree; assert.typeof(tag, 'string'); @@ -318,22 +307,6 @@ const decodeToJustin = (encoding, shouldIndent = false, slots = []) => { // TODO deprecated. Eventually remove. return out.next('Symbol.asyncIterator'); } - case 'symbol': { - const { name } = rawTree; - assert.typeof(name, 'string'); - const sym = passableSymbolForName(name); - assert.typeof(sym, 'symbol'); - const registeredName = Symbol.keyFor(sym); - if (registeredName === undefined) { - const match = AtAtPrefixPattern.exec(name); - assert(match !== null); - const suffix = match[1]; - assert(Symbol[suffix] === sym); - assert(identPattern.test(suffix)); - return out.next(`Symbol.${suffix}`); - } - return out.next(`Symbol.for(${quote(registeredName)})`); - } case 'tagged': { const { tag, payload } = rawTree; out.next(`makeTagged(${quote(tag)},`); diff --git a/packages/marshal/src/rankOrder.js b/packages/marshal/src/rankOrder.js index 05ef1503b2..81a0f0c00c 100644 --- a/packages/marshal/src/rankOrder.js +++ b/packages/marshal/src/rankOrder.js @@ -1,4 +1,4 @@ -import { getTag, passStyleOf, nameForPassableSymbol } from '@endo/pass-style'; +import { getTag, passStyleOf } from '@endo/pass-style'; import { Fail, q } from '@endo/errors'; import { passStylePrefixes, @@ -150,12 +150,6 @@ export const makeComparatorKit = (compareRemotables = (_x, _y) => NaN) => { return 1; } } - case 'symbol': { - return comparator( - nameForPassableSymbol(left), - nameForPassableSymbol(right), - ); - } case 'number': { // `NaN`'s rank is after all other numbers. if (Number.isNaN(left)) { diff --git a/packages/marshal/src/types.js b/packages/marshal/src/types.js index 8f73c6c936..78a95ca834 100644 --- a/packages/marshal/src/types.js +++ b/packages/marshal/src/types.js @@ -31,8 +31,6 @@ export {}; * EncodingClass<'Infinity'> | * EncodingClass<'-Infinity'> | * EncodingClass<'bigint'> & { digits: string } | - * EncodingClass<'@@asyncIterator'> | - * EncodingClass<'symbol'> & { name: string } | * EncodingClass<'error'> & { name: string, * message: string, * errorId?: string, @@ -50,7 +48,8 @@ export {}; * } * } EncodingUnion * - * Note that the '@@asyncIterator' encoding is deprecated. Use 'symbol' instead. + * Note that the '@@asyncIterator' and 'symbol' encodings are no longer + * supported. * * The 'hilbert' encoding is a reference to the Hilbert Hotel * of https://www.ias.edu/ideas/2016/pires-hilbert-hotel . diff --git a/packages/marshal/test/_marshal-test-data.js b/packages/marshal/test/_marshal-test-data.js index fcdc680a55..7ed99ce453 100644 --- a/packages/marshal/test/_marshal-test-data.js +++ b/packages/marshal/test/_marshal-test-data.js @@ -48,14 +48,6 @@ export const roundTripPairs = harden([ // Does not fit into a number [9007199254740993n, { '@qclass': 'bigint', digits: '9007199254740993' }], - // Well known symbols - [Symbol.asyncIterator, { '@qclass': 'symbol', name: '@@asyncIterator' }], - [Symbol.match, { '@qclass': 'symbol', name: '@@match' }], - // Registered symbols - [Symbol.for('foo'), { '@qclass': 'symbol', name: 'foo' }], - // Registered symbol hilbert hotel - [Symbol.for('@@foo'), { '@qclass': 'symbol', name: '@@@@foo' }], - // Normal json reviver cannot make properties with undefined values [[undefined], [{ '@qclass': 'undefined' }]], [{ foo: undefined }, { foo: { '@qclass': 'undefined' } }], @@ -181,10 +173,6 @@ export const jsonJustinPairs = harden([ ['{"@qclass":"-Infinity"}', '-Infinity'], ['{"@qclass":"bigint","digits":"4"}', '4n'], ['{"@qclass":"bigint","digits":"9007199254740993"}', '9007199254740993n'], - ['{"@qclass":"symbol","name":"@@asyncIterator"}', 'Symbol.asyncIterator'], - ['{"@qclass":"symbol","name":"@@match"}', 'Symbol.match'], - ['{"@qclass":"symbol","name":"foo"}', 'Symbol.for("foo")'], - ['{"@qclass":"symbol","name":"@@@@foo"}', 'Symbol.for("@@foo")'], // Arrays and objects ['[{"@qclass":"undefined"}]', '[undefined]'], @@ -264,11 +252,8 @@ export const unsortedSample = harden([ [5], exampleAlice, [], - Symbol.for('foo'), Error('not erroneous'), - Symbol.for('@@foo'), [5, { bar: 5 }], - Symbol.for(''), false, exampleCarol, [exampleCarol, 'm'], @@ -291,7 +276,6 @@ export const unsortedSample = harden([ ['b', 3], ]), Infinity, - Symbol.isConcatSpreadable, [5, { foo: 4, bar: undefined }], Promise.resolve('fulfillment'), [5, { foo: 4 }], @@ -385,10 +369,6 @@ export const sortedSample = harden([ 'foo', null, - Symbol.for(''), - Symbol.for('@@foo'), - Symbol.isConcatSpreadable, - Symbol.for('foo'), undefined, undefined, diff --git a/packages/marshal/test/marshal-capdata.test.js b/packages/marshal/test/marshal-capdata.test.js index 90e7d10819..e842c77d17 100644 --- a/packages/marshal/test/marshal-capdata.test.js +++ b/packages/marshal/test/marshal-capdata.test.js @@ -61,8 +61,8 @@ test('serialize static data', t => { t.deepEqual(ser(-0), ser(0)); // unregistered symbols t.throws(() => ser(Symbol('sym2')), { - // An anonymous symbol is not Passable - message: /Only registered symbols or well-known symbols are passable:/, + // A symbol is not Passable + message: 'Unrecognized typeof "symbol"', }); const cd = ser(harden([1, 2])); diff --git a/packages/marshal/test/marshal-smallcaps.test.js b/packages/marshal/test/marshal-smallcaps.test.js index 87ed067ba3..bcf40fa226 100644 --- a/packages/marshal/test/marshal-smallcaps.test.js +++ b/packages/marshal/test/marshal-smallcaps.test.js @@ -53,10 +53,9 @@ test('smallcaps serialize static data', t => { t.deepEqual(ser(0), { body: '#0', slots: [] }); t.deepEqual(ser(-0), { body: '#0', slots: [] }); t.deepEqual(ser(-0), ser(0)); - // unregistered symbols + // symbols t.throws(() => ser(Symbol('sym2')), { - // An anonymous symbol is not Passable - message: /Only registered symbols or well-known symbols are passable:/, + message: 'Unrecognized typeof "symbol"', }); const cd = ser(harden([1, 2])); @@ -324,7 +323,6 @@ test('smallcaps records', t => { * * `+` - non-negative bigint * * `-` - negative bigint * * `#` - manifest constant - * * `%` - symbol * * `$` - remotable * * `&` - promise */ @@ -366,16 +364,6 @@ test('smallcaps encoding examples', t => { assertRoundTrip('-escaped', `#"!-escaped"`, [], 'escaped -'); assertRoundTrip('%escaped', `#"!%escaped"`, [], 'escaped %'); - // Symbols - assertRoundTrip(Symbol.iterator, '#"%@@iterator"', [], 'well known symbol'); - assertRoundTrip(Symbol.for('foo'), '#"%foo"', [], 'reg symbol'); - assertRoundTrip( - Symbol.for('@@foo'), - '#"%@@@@foo"', - [], - 'reg symbol that looks well known', - ); - // Remotables const foo = Far('foo', {}); const bar = Far('bar', { diff --git a/packages/module-source/test/fixtures/exportheavy.js b/packages/module-source/test/fixtures/exportheavy.js index ef14e708ee..d26791f524 100644 --- a/packages/module-source/test/fixtures/exportheavy.js +++ b/packages/module-source/test/fixtures/exportheavy.js @@ -13,11 +13,6 @@ export { export { getErrorConstructor, toPassableError } from './src/helpers/error.js'; export { getInterfaceOf } from './src/helpers/remotable.js'; -export { - nameForPassableSymbol, - passableSymbolForName, -} from './src/helpers/symbol.js'; - export { passStyleOf, assertPassable } from './src/passStyleOf.js'; export { deeplyFulfilled } from './src/deeplyFulfilled.js'; @@ -42,9 +37,6 @@ export { // eslint-disable-next-line import/export export * from './src/types.js'; - -const { details: X, Fail } = assert; - // This is a pathological minimum, but exercised by the unit test. export const MIN_DATA_BUFFER_LENGTH = 1; diff --git a/packages/pass-style/index.js b/packages/pass-style/index.js index d28c3ae77f..4218bb07c3 100644 --- a/packages/pass-style/index.js +++ b/packages/pass-style/index.js @@ -11,13 +11,6 @@ export { getErrorConstructor, isErrorLike } from './src/error.js'; export { getInterfaceOf } from './src/remotable.js'; -export { - assertPassableSymbol, - isPassableSymbol, - nameForPassableSymbol, - passableSymbolForName, -} from './src/symbol.js'; - export { isWellFormedString, assertWellFormedString, diff --git a/packages/pass-style/src/passStyleOf.js b/packages/pass-style/src/passStyleOf.js index 7c4dd78b2e..2861de67f3 100644 --- a/packages/pass-style/src/passStyleOf.js +++ b/packages/pass-style/src/passStyleOf.js @@ -18,7 +18,6 @@ import { } from './error.js'; import { RemotableHelper } from './remotable.js'; -import { assertPassableSymbol } from './symbol.js'; import { assertSafePromise } from './safe-promise.js'; import { assertPassableString } from './string.js'; @@ -135,10 +134,6 @@ const makePassStyleOf = passStyleHelpers => { assertPassableString(inner); return 'string'; } - case 'symbol': { - assertPassableSymbol(inner); - return 'symbol'; - } case 'object': { if (inner === null) { return 'null'; diff --git a/packages/pass-style/src/symbol.js b/packages/pass-style/src/symbol.js deleted file mode 100644 index ca01808206..0000000000 --- a/packages/pass-style/src/symbol.js +++ /dev/null @@ -1,117 +0,0 @@ -import { Fail, q } from '@endo/errors'; - -const { ownKeys } = Reflect; - -/** - * The well known symbols are static symbol values on the `Symbol` constructor. - */ -const wellKnownSymbolNames = new Map( - ownKeys(Symbol) - .filter( - name => typeof name === 'string' && typeof Symbol[name] === 'symbol', - ) - .filter(name => { - // @ts-expect-error It doesn't know name cannot be a symbol - !name.startsWith('@@') || - Fail`Did not expect Symbol to have a symbol-valued property name starting with "@@" ${q( - name, - )}`; - return true; - }) - // @ts-ignore It doesn't know name cannot be a symbol - .map(name => [Symbol[name], `@@${name}`]), -); - -/** - * The passable symbols are the well known symbols (the symbol values - * of static properties of the `Symbol` constructor) and the registered - * symbols. - * - * @param {any} sym - * @returns {boolean} - */ -export const isPassableSymbol = sym => - typeof sym === 'symbol' && - (typeof Symbol.keyFor(sym) === 'string' || wellKnownSymbolNames.has(sym)); -harden(isPassableSymbol); - -export const assertPassableSymbol = sym => - isPassableSymbol(sym) || - Fail`Only registered symbols or well-known symbols are passable: ${q(sym)}`; -harden(assertPassableSymbol); - -/** - * If `sym` is a passable symbol, return a string that uniquely identifies this - * symbol. If `sym` is a non-passable symbol, return `undefined`. - * - * The passable symbols are the well known symbols (the symbol values - * of static properties of the `Symbol` constructor) and the registered - * symbols. Since the registration string of a registered symbol can be any - * string, if we simply used that to identify those symbols, there would not - * be any remaining strings left over to identify the well-known symbols. - * Instead, we reserve strings beginning with `"@@"` for purposes of this - * encoding. We identify a well known symbol such as `Symbol.iterator` - * by prefixing the property name with `"@@"`, such as `"@@iterator"`. - * For registered symbols whose name happens to begin with `"@@"`, such - * as `Symbol.for('@@iterator')` or `Symbol.for('@@foo')`, we identify - * them by prefixing them with an extra `"@@"`, such as - * `"@@@@iterator"` or `"@@@@foo"`. (This is the Hilbert Hotel encoding - * technique.) - * - * @param {symbol} sym - * @returns {string=} - */ -export const nameForPassableSymbol = sym => { - const name = Symbol.keyFor(sym); - if (name === undefined) { - return wellKnownSymbolNames.get(sym); - } - if (name.startsWith('@@')) { - return `@@${name}`; - } - return name; -}; -harden(nameForPassableSymbol); - -const AtAtPrefixPattern = /^@@(.*)$/; -harden(AtAtPrefixPattern); - -/** - * If `name` is a string that could have been produced by - * `nameForPassableSymbol`, return the symbol argument it was produced to - * represent. - * - * If `name` does not begin with `"@@"`, then just the corresponding - * registered symbol, `Symbol.for(name)`. - * If `name` is `"@@"` followed by a well known symbol's property name on - * `Symbol` such `"@@iterator", return that well known symbol such as - * `Symbol.iterator` - * If `name` begins with `"@@@@"` it encodes the registered symbol whose - * name begins with `"@@"` instead. - * Otherwise, if name begins with `"@@"` it may encode a registered symbol - * from a future version of JavaScript, but it is not one we can decode - * yet, so throw. - * - * @param {string} name - * @returns {symbol=} - */ -export const passableSymbolForName = name => { - if (typeof name !== 'string') { - return undefined; - } - const match = AtAtPrefixPattern.exec(name); - if (match) { - const suffix = match[1]; - if (suffix.startsWith('@@')) { - return Symbol.for(suffix); - } else { - const sym = Symbol[suffix]; - if (typeof sym === 'symbol') { - return sym; - } - Fail`Reserved for well known symbol ${q(suffix)}: ${q(name)}`; - } - } - return Symbol.for(name); -}; -harden(passableSymbolForName); diff --git a/packages/pass-style/src/types.d.ts b/packages/pass-style/src/types.d.ts index fdcd419a74..69c95bcca6 100644 --- a/packages/pass-style/src/types.d.ts +++ b/packages/pass-style/src/types.d.ts @@ -19,8 +19,7 @@ export type PrimitiveStyle = | 'boolean' | 'number' | 'bigint' - | 'string' - | 'symbol'; + | 'string'; export type ContainerStyle = 'copyRecord' | 'copyArray' | 'tagged'; @@ -64,7 +63,7 @@ export type PassByRef = * and is classified by PassStyle: * * Atomic primitive values have a PrimitiveStyle (PassStyle * 'undefined' | 'null' | 'boolean' | 'number' | 'bigint' - * | 'string' | 'symbol'). (Passable considers `void` to be `undefined`.) + * | 'string'). (Passable considers `void` to be `undefined`.) * * Containers aggregate other Passables into * * sequences as CopyArrays (PassStyle 'copyArray'), or * * string-keyed dictionaries as CopyRecords (PassStyle 'copyRecord'), or @@ -101,7 +100,6 @@ export type PassStyleOf = { (p: boolean): 'boolean'; (p: number): 'number'; (p: bigint): 'bigint'; - (p: symbol): 'symbol'; (p: null): 'null'; (p: Promise): 'promise'; (p: Error): 'error'; diff --git a/packages/pass-style/src/types.test-d.ts b/packages/pass-style/src/types.test-d.ts index 274e54a294..6e61cb6043 100644 --- a/packages/pass-style/src/types.test-d.ts +++ b/packages/pass-style/src/types.test-d.ts @@ -18,7 +18,6 @@ expectType<'string'>(passStyleOf('str')); expectType<'boolean'>(passStyleOf(true)); expectType<'number'>(passStyleOf(1)); expectType<'bigint'>(passStyleOf(1n)); -expectType<'symbol'>(passStyleOf(Symbol.for('foo'))); expectType<'null'>(passStyleOf(null)); expectType<'promise'>(passStyleOf(Promise.resolve())); expectType<'error'>(passStyleOf(new Error())); diff --git a/packages/pass-style/test/passStyleOf.test.js b/packages/pass-style/test/passStyleOf.test.js index d09cd55260..41797f71dc 100644 --- a/packages/pass-style/test/passStyleOf.test.js +++ b/packages/pass-style/test/passStyleOf.test.js @@ -24,8 +24,6 @@ test('passStyleOf basic success cases', t => { t.is(passStyleOf(true), 'boolean'); t.is(passStyleOf(33), 'number'); t.is(passStyleOf(33n), 'bigint'); - t.is(passStyleOf(Symbol.for('foo')), 'symbol'); - t.is(passStyleOf(Symbol.iterator), 'symbol'); t.is(passStyleOf(null), 'null'); t.is(passStyleOf(harden(Promise.resolve(null))), 'promise'); t.is(passStyleOf(harden([3, 4])), 'copyArray'); @@ -52,8 +50,7 @@ test('some passStyleOf rejections', t => { }); t.throws(() => passStyleOf(Symbol('unique')), { - message: - /Only registered symbols or well-known symbols are passable: "\[Symbol\(unique\)\]"/, + message: 'Unrecognized typeof "symbol"', }); if (harden.isFake) { t.is(passStyleOf({}), 'copyRecord'); diff --git a/packages/pass-style/tools/arb-passable.js b/packages/pass-style/tools/arb-passable.js index 5c6bcbdfbf..c710603398 100644 --- a/packages/pass-style/tools/arb-passable.js +++ b/packages/pass-style/tools/arb-passable.js @@ -17,15 +17,6 @@ export const arbString = fc.oneof(fc.string(), fc.fullUnicodeString()); const keyableLeaves = [ fc.constantFrom(null, undefined, false, true), arbString, - arbString.map(s => Symbol.for(s)), - // primordial symbols and registered lookalikes - fc.constantFrom( - ...Object.getOwnPropertyNames(Symbol).flatMap(k => { - const v = Symbol[k]; - if (typeof v !== 'symbol') return []; - return [v, Symbol.for(k), Symbol.for(`@@${k}`)]; - }), - ), fc.bigInt(), fc.integer(), fc.constantFrom(-0, NaN, Infinity, -Infinity), diff --git a/packages/patterns/src/keys/compareKeys.js b/packages/patterns/src/keys/compareKeys.js index b68bc3b84c..8c30cc18dd 100644 --- a/packages/patterns/src/keys/compareKeys.js +++ b/packages/patterns/src/keys/compareKeys.js @@ -102,10 +102,6 @@ export const compareKeys = (left, right) => { case 'boolean': case 'bigint': case 'string': - case 'symbol': { - // for these, keys compare the same as rank - return compareRank(left, right); - } case 'number': { const rankComp = compareRank(left, right); if (rankComp === 0) { diff --git a/packages/patterns/src/patterns/getGuardPayloads.js b/packages/patterns/src/patterns/getGuardPayloads.js index 3aef72ba79..f592cd5143 100644 --- a/packages/patterns/src/patterns/getGuardPayloads.js +++ b/packages/patterns/src/patterns/getGuardPayloads.js @@ -14,7 +14,6 @@ import { matches, mustMatch, } from './patternMatchers.js'; -import { getCopyMapKeys, makeCopyMap } from '../keys/checkKey.js'; /** * @import {AwaitArgGuard, AwaitArgGuardPayload, InterfaceGuard, InterfaceGuardPayload, MethodGuard, MethodGuardPayload} from '../types.js' @@ -206,7 +205,6 @@ const LegacyInterfaceGuardShape = M.splitRecord( // There is no need to accommodate LegacyMethodGuardShape in // this position, since `symbolMethodGuards happened // after https://github.com/endojs/endo/pull/1712 - symbolMethodGuards: M.mapOf(M.symbol(), MethodGuardShape), }, ); @@ -265,21 +263,15 @@ export const getInterfaceGuardPayload = interfaceGuard => { }; harden(getInterfaceGuardPayload); -const emptyCopyMap = makeCopyMap([]); - /** * @param {InterfaceGuard} interfaceGuard * @returns {(string | symbol)[]} */ export const getInterfaceMethodKeys = interfaceGuard => { - const { methodGuards, symbolMethodGuards = emptyCopyMap } = - getInterfaceGuardPayload(interfaceGuard); + const { methodGuards } = getInterfaceGuardPayload(interfaceGuard); /** @type {(string | symbol)[]} */ // TODO at-ts-expect-error works locally but not from @endo/exo // @ts-ignore inference is too weak to see this is ok - return harden([ - ...Reflect.ownKeys(methodGuards), - ...getCopyMapKeys(symbolMethodGuards), - ]); + return harden([...Reflect.ownKeys(methodGuards)]); }; harden(getInterfaceMethodKeys); diff --git a/packages/patterns/src/patterns/patternMatchers.js b/packages/patterns/src/patterns/patternMatchers.js index 8cc6815f7f..a31b322a4a 100644 --- a/packages/patterns/src/patterns/patternMatchers.js +++ b/packages/patterns/src/patterns/patternMatchers.js @@ -7,7 +7,6 @@ import { makeTagged, passStyleOf, hasOwnPropertyOf, - nameForPassableSymbol, compareRank, getPassStyleCover, intersectRankCovers, @@ -32,7 +31,6 @@ import { copyMapKeySet, checkCopyBag, getCopyMapEntryArray, - makeCopyMap, } from '../keys/checkKey.js'; import { generateCollectionPairEntries } from '../keys/keycollection-operators.js'; @@ -66,7 +64,6 @@ let MM; export const defaultLimits = harden({ decimalDigitsLimit: 100, stringLengthLimit: 100_000, - symbolNameLengthLimit: 100, numPropertiesLimit: 80, propertyNameLengthLimit: 100, arrayLengthLimit: 10_000, @@ -440,7 +437,6 @@ const makePatternKit = () => { case 'number': case 'bigint': case 'string': - case 'symbol': case 'copySet': case 'copyBag': case 'remotable': { @@ -978,38 +974,6 @@ const makePatternKit = () => { getPassStyleCover('string'), }); - /** @type {MatchHelper} */ - const matchSymbolHelper = Far('match:symbol helper', { - checkMatches: (specimen, [limits = undefined], check) => { - const { symbolNameLengthLimit } = limit(limits); - if (!checkKind(specimen, 'symbol', check)) { - return false; - } - const symbolName = nameForPassableSymbol(specimen); - - if (typeof symbolName !== 'string') { - throw Fail`internal: Passable symbol ${specimen} must have a passable name`; - } - return check( - symbolName.length <= symbolNameLengthLimit, - X`Symbol name ${q( - symbolName, - )} must not be bigger than ${symbolNameLengthLimit}`, - ); - }, - - checkIsWellFormed: (payload, check) => - checkIsWellFormedWithLimit( - payload, - harden([]), - check, - 'match:symbol payload', - ), - - getRankCover: (_matchPayload, _encodePassable) => - getPassStyleCover('symbol'), - }); - /** @type {MatchHelper} */ const matchRemotableHelper = Far('match:remotable helper', { checkMatches: (specimen, remotableDesc, check) => { @@ -1536,7 +1500,6 @@ const makePatternKit = () => { 'match:bigint': matchBigintHelper, 'match:nat': matchNatHelper, 'match:string': matchStringHelper, - 'match:symbol': matchSymbolHelper, 'match:remotable': matchRemotableHelper, 'match:lt': matchLTHelper, @@ -1570,7 +1533,6 @@ const makePatternKit = () => { const BigIntShape = makeTagged('match:bigint', []); const NatShape = makeTagged('match:nat', []); const StringShape = makeTagged('match:string', []); - const SymbolShape = makeTagged('match:symbol', []); const RecordShape = makeTagged('match:recordOf', [AnyShape, AnyShape]); const ArrayShape = makeTagged('match:arrayOf', [AnyShape]); const SetShape = makeTagged('match:setOf', [AnyShape]); @@ -1647,8 +1609,6 @@ const makePatternKit = () => { limits ? makeLimitsMatcher('match:nat', [limits]) : NatShape, string: (limits = undefined) => limits ? makeLimitsMatcher('match:string', [limits]) : StringShape, - symbol: (limits = undefined) => - limits ? makeLimitsMatcher('match:symbol', [limits]) : SymbolShape, record: (limits = undefined) => limits ? M.recordOf(M.any(), M.any(), limits) : RecordShape, // struct: A pattern that matches CopyRecords with a fixed quantity of @@ -1934,7 +1894,6 @@ export const InterfaceGuardPayloadShape = M.splitRecord( { defaultGuards: M.or(M.undefined(), 'passable', 'raw'), sloppy: M.boolean(), - symbolMethodGuards: M.mapOf(M.symbol(), MethodGuardShape), }, ); @@ -1959,28 +1918,16 @@ harden(assertInterfaceGuard); const makeInterfaceGuard = (interfaceName, methodGuards, options = {}) => { const { sloppy = false, defaultGuards = sloppy ? 'passable' : undefined } = options; - // For backwards compatibility, string-keyed method guards are represented in - // a CopyRecord. But symbol-keyed methods cannot be, so we put those in a - // CopyMap when present. /** @type {Record} */ const stringMethodGuards = {}; - /** @type {Array<[symbol, MethodGuard]>} */ - const symbolMethodGuardsEntries = []; for (const key of ownKeys(methodGuards)) { const value = methodGuards[/** @type {string} */ (key)]; - if (typeof key === 'symbol') { - symbolMethodGuardsEntries.push([key, value]); - } else { - stringMethodGuards[key] = value; - } + stringMethodGuards[key] = value; } /** @type {InterfaceGuard} */ const result = makeTagged('guard:interfaceGuard', { interfaceName, methodGuards: stringMethodGuards, - ...(symbolMethodGuardsEntries.length - ? { symbolMethodGuards: makeCopyMap(symbolMethodGuardsEntries) } - : {}), defaultGuards, }); assertInterfaceGuard(result); diff --git a/packages/patterns/src/types.js b/packages/patterns/src/types.js index e84eb7fea2..426dff36b8 100644 --- a/packages/patterns/src/types.js +++ b/packages/patterns/src/types.js @@ -501,8 +501,6 @@ export {}; * interfaceName: string, * methodGuards: * Omit & Partial<{ [K in Extract]: never }>, - * symbolMethodGuards?: - * CopyMap, T[Extract]>, * defaultGuards?: DefaultGuardType, * sloppy?: boolean, * }} InterfaceGuardPayload diff --git a/packages/patterns/test/pattern-limits.test.js b/packages/patterns/test/pattern-limits.test.js index 04c882ac94..1b33af36f3 100644 --- a/packages/patterns/test/pattern-limits.test.js +++ b/packages/patterns/test/pattern-limits.test.js @@ -115,33 +115,6 @@ const runTests = (successCase, failCase) => { /^string "(x+)" must not be bigger than 100000$/, ); } - // symbolNameLengthLimit - { - const specimen = Symbol.for('moderate length string'); - successCase(specimen, M.symbol()); - successCase(specimen, M.symbol(harden({ symbolNameLengthLimit: 40 }))); - - failCase( - specimen, - M.symbol(harden({ symbolNameLengthLimit: 10 })), - 'Symbol name "moderate length string" must not be bigger than 10', - ); - } - { - const specimen = Symbol.for( - 'x'.repeat(defaultLimits.symbolNameLengthLimit + 1), - ); - successCase( - specimen, - M.symbol(harden({ symbolNameLengthLimit: Infinity })), - ); - - failCase( - specimen, - M.symbol(), - /^Symbol name "(x+)" must not be bigger than 100$/, - ); - } // numPropertiesLimit, propertyNameLengthLimit { const specimen = { diff --git a/packages/patterns/test/patterns.test.js b/packages/patterns/test/patterns.test.js index f5279579df..693e5c3658 100644 --- a/packages/patterns/test/patterns.test.js +++ b/packages/patterns/test/patterns.test.js @@ -50,7 +50,6 @@ const runTests = (t, successCase, failCase) => { number: (repr, kind) => `${kind} ${repr} - Must be a number`, bigint: (repr, kind) => `${kind} ${repr} - Must be a bigint`, string: (repr, kind) => `${kind} ${repr} - Must be a string`, - symbol: (repr, kind) => `${kind} ${repr} - Must be a symbol`, record: (repr, kind) => `${kind} ${repr} - Must be a copyRecord`, array: (repr, kind) => `${kind} ${repr} - Must be a copyArray`, set: (repr, kind) => `${kind} ${repr} - Must be a copySet`,