Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(exo): Extend InterfaceGuard to support symbol-keyed methods #1740

Merged
merged 1 commit into from
Aug 27, 2023

Conversation

gibson042
Copy link
Contributor

Fixes #1728

Description

Extend InterfaceGuard with a symbolMethodGuards field whose value is a CopyMap<symbol, MethodGuard> when the interface has symbol-keyed methods such as Symbol.asyncIterator. The current implementation expresses it as completely optional and does not create it when there are no symbol-keyed methods, but we could also set it to an empty CopyMap in that case.

Security Considerations

None AFAICT.

Scaling Considerations

None AFAICT, even if we always add the CopyMap.

Documentation Considerations

None.

Testing Considerations

Just unit tests.

Upgrade Considerations

None special; the new functionality should be fully backwards compatible.

@gibson042 gibson042 requested a review from erights August 26, 2023 19:49
Copy link
Contributor

@erights erights left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First quick reaction: Awesome choice to use a CopyMap rather than an array of pairs! In thinking about this issue, that "natural" choice never occurred to me.

(Good you're also fixing CopyMap patterns, just in time for the first production use of CopyMaps!)

@erights
Copy link
Contributor

erights commented Aug 27, 2023

expresses it as completely optional and does not create it when there are no symbol-keyed methods, but we could also set it to an empty CopyMap in that case.

Since it arrives late, after an earlier representation shipped, and optional is coherent. I think it should remain optional. But if it does happen to be present with an empty map, that should be fine too. I don't see any reason to insist on a canonical representation for this case. (I think you're already doing that, in which case, no change suggested.)

Copy link
Contributor

@erights erights left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks! For the sake of agoric-sdk, it's great that we can get this into the next endo release.

@@ -10,13 +10,19 @@ When an exo is defined with an InterfaceGuard, the exo is augmented by default w

```js
// `GET_INTERFACE_GUARD` holds the name of the meta-method
import { GET_INTERFACE_GUARD } from `@endo/exo`;
import { GET_INTERFACE_GUARD } from '@endo/exo';
import { getCopyMapKeys } from '@endo/patterns';

...
const interfaceGuard = await E(exo)[GET_INTERFACE_GUARD]();
// `methodNames` omits names of automatically added meta-methods like
// the value of `GET_INTERFACE_GUARD`.
// Others may also be omitted if `interfaceGuard.partial`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attn @michaelfig

My mistake! In anything that saw the light of day, it was never called interfaceGuard.partial. It became interfaceGuard.sloppy, but I forgot to rename this occurrence.

But @michaelfig is in process with a PR that will make changes in this area, so leave that to him. For your PR, no change suggested.

Comment on lines 21 to 26
const methodNames = Reflect.ownKeys(interfaceGuard.methodGuards)
.concat(
interfaceGuard.symbolMethodGuards
? getCopyMapKeys(interfaceGuard.symbolMethodGuards)
: []
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the following style a bit better, but up to you.

Suggested change
const methodNames = Reflect.ownKeys(interfaceGuard.methodGuards)
.concat(
interfaceGuard.symbolMethodGuards
? getCopyMapKeys(interfaceGuard.symbolMethodGuards)
: []
);
const methodNames = [
...Reflect.ownKeys(interfaceGuard.methodGuards),
...interfaceGuard.symbolMethodGuards
? getCopyMapKeys(interfaceGuard.symbolMethodGuards)
: [],
];

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment on lines +273 to +277
methodGuards = harden({
...mg,
...(symbolMethodGuards &&
fromEntries(getCopyMapEntries(symbolMethodGuards))),
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Given this, my preference to use [...x, ...y] above is stronger. Now I will request that change ;)

t.is(UpCounterI.symbolMethodGuards, undefined);

const symbolic = Symbol.for('symbolic');
const FooI = M.interface('Foo', {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also add a test with an exo implementing FooI and then call the symbol-named method to test that the raw method is guarded by the methodGuard.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

klass: 'Interface',
interfaceName: M.string(),
methodGuards: M.recordOf(M.string(), MethodGuardShape),
sloppy: M.boolean(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just be aware that as of @michaelfig 's upcoming PR, sloppy will move into that optional section, and another will appear there as well. No change suggested.

Comment on lines 517 to 518
* methodGuards: { [K in keyof T]: K extends symbol ? never : T[K] },
* symbolMethodGuards?: CopyMap<symbol, MethodGuard>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice typing of methodGuards. I wondered how to do that.

Could you use the same trick to type symbolMethodGuard with the opposing side of that conditional?

Attn @turadg

I think doing so will help @turadg 's efforts to statically inter TS types from patterns and guards.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got it to type the CopyMap K as a symbol-keyed entry of T, but don't know how to establish the pair relationship. It will be open for followup.

Comment on lines +1853 to +1855
...(symbolMethodGuardsEntries.length
? { symbolMethodGuards: makeCopyMap(symbolMethodGuardsEntries) }
: {}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That ... (x ? {y} : {}) is quite cute. No change suggested.

@gibson042 gibson042 force-pushed the gibson-1728-symbol-keyed-methodguards branch from 3a2223f to 72101f9 Compare August 27, 2023 16:03
@gibson042 gibson042 merged commit d6ea36b into master Aug 27, 2023
@gibson042 gibson042 deleted the gibson-1728-symbol-keyed-methodguards branch August 27, 2023 16:11
gibson042 added a commit that referenced this pull request Aug 30, 2023
gibson042 added a commit that referenced this pull request Aug 30, 2023
gibson042 added a commit that referenced this pull request Aug 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Inconsistency between Remotable rules and InterfaceGuard pattern language
2 participants