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

export types #6500

Merged
merged 26 commits into from
Nov 1, 2022
Merged

export types #6500

merged 26 commits into from
Nov 1, 2022

Conversation

turadg
Copy link
Member

@turadg turadg commented Oct 26, 2022

refs: #6343

Description

Emit types for agoric-sdk package builds like endojs/endo#1307

Security Considerations

n/a

Documentation Considerations

Export types are a documentation resource.

Testing Considerations

CI. And dry release?

@turadg turadg requested review from kriskowal and mhofman October 26, 2022 22:20
Copy link
Member

@mhofman mhofman left a comment

Choose a reason for hiding this comment

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

Nice start. Not an approval until I can get some clarifications on the various ts-expect-error.

I'd like to at least double check the need for some of these ts-expect-errors. As I've expressed before, I believe they are worse than casts as they can hide multiple errors unexpectedly. If possible narrow application of casts are better (while slightly harder to read unfortunately).

Also I see there was an attempt to switch to exported types, but it was reverted. If attempted again, let's avoid deep imports cross package.

I have some type fixes for swingset that I may now try to brush off :)

packages/internal/src/utils.js Show resolved Hide resolved
packages/internal/src/utils.js Show resolved Hide resolved
// eslint-disable-next-line import/no-extraneous-dependencies
import '@agoric/swingset-vat/src/types-ambient.js';
Copy link
Member

Choose a reason for hiding this comment

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

I don't suppose we can avoid relying on ambient types for swingset-vat. I know it does re-export most types explicitly at the top level.

@@ -158,7 +158,7 @@ const FIRST_METER_ID = 1n;

/**
* @param {HostStore} hostStorage
* @param {KernelSlog} kernelSlog
* @param {KernelSlog | null} kernelSlog
Copy link
Member

Choose a reason for hiding this comment

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

Oh I have a stash with this fix and other swingset ones somewhere

Comment on lines 70 to 71
/** @type {<T>(store: ERef<MapStore>, key: string, make: () => T) => Promise<T>} */
/** @type {<T>(store: ERef<Map<string, T>>, key: string, make: () => T) => Promise<T>} */
Copy link
Member

Choose a reason for hiding this comment

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

I'm surprised we have a Map based store around

Copy link
Member

Choose a reason for hiding this comment

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

provideWhen seem to be used once with a ERef<MapStore> and once with a Map. The semantics of these Maps are different enough, which I believe does reflect on their signature. If provideWhen is in fact using the common subset of these 2, can we be explicit about this somehow? Since TS is structural typing only, maybe by defining an interface of the subset used? That would avoid a cast / expect-error in the place where provideWhen is used with the ERef<MapStore>.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good idea. Done.

packages/vats/src/repl.js Outdated Show resolved Hide resolved
packages/vats/src/vat-provisioning.js Outdated Show resolved Hide resolved
packages/inter-protocol/src/proposals/utils.js Outdated Show resolved Hide resolved
packages/inter-protocol/src/proposals/utils.js Outdated Show resolved Hide resolved
packages/vats/src/types.js Show resolved Hide resolved
@turadg turadg force-pushed the 1254-export-types branch 2 times, most recently from fd324c8 to 8980a2d Compare October 28, 2022 23:19
@turadg turadg marked this pull request as ready for review October 28, 2022 23:19
@mhofman
Copy link
Member

mhofman commented Oct 28, 2022

Nit on reviewing process: While I understand this is was still a draft PR, it's extremely difficult to track changes compared to the previously reviewed state if force pushes include both amendments and base changes. In general please do not amend, and stick to commits additions once reviews have started, and until the PR is accepted. New commits can be marked as fixup to indicate such amendments are to be made just before merging only. Furthermore when changing the base, please do 2 force push: one push adding commits on the old base as is, and one force push rebasing showing no changes (or only conflict resolution if warranted).

Another point specific to this PR: please include the main package name affected in the conventional commit prefix, e.g. chore(ERTP). Right now there are commits with duplicate names making it impossible to understand what's going on.

I really want type improvements, but right now this PR is extremely difficult to review.

@mhofman mhofman self-requested a review October 28, 2022 23:34
@turadg
Copy link
Member Author

turadg commented Oct 28, 2022

I agree with the amendment policy for PRs marked R4R. I don't for PRs that aren't. This is something our eng org should agree on so let's discuss in standup.

Another point specific to this PR: please include the main package name affected in the conventional commit prefix, e.g. chore(ERTP).

I've opted against that because IIUC it creates redundant info in READMEs. e.g. the @agoric/ertp changelog says "chore(ertp): foo".

Right now there are commits with duplicate names making it impossible to understand what's going on.

I'm confused on why omission of package name makes it impossible to understand what's going on. If I had not separated the commits and instead, for example, squashed all the chore: misc types fixes then there would be no duplicates but I expect it would be harder to follow the changes.

I really want type improvements, but right now this PR is extremely difficult to review.

All the changes since your review of the draft were addressing your comments. So maybe it suffices to look over your comments and see whether they were addressed to your satisfaction.

@turadg turadg force-pushed the 1254-export-types branch from 8f791aa to 8980a2d Compare October 31, 2022 14:41
Copy link
Member

@mhofman mhofman left a comment

Choose a reason for hiding this comment

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

I'd like to do another pass, but here is my review so far.

I still have some concerns regarding casts and type compatibility.

I believe the conversion of the vats package to exported type introduces some mistaken re-exports, and could use a better layering for the main entrypoint.

packages/smart-wallet/package.json Show resolved Hide resolved
Comment on lines 70 to 71
/** @type {<T>(store: ERef<MapStore>, key: string, make: () => T) => Promise<T>} */
/** @type {<T>(store: ERef<Map<string, T>>, key: string, make: () => T) => Promise<T>} */
Copy link
Member

Choose a reason for hiding this comment

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

provideWhen seem to be used once with a ERef<MapStore> and once with a Map. The semantics of these Maps are different enough, which I believe does reflect on their signature. If provideWhen is in fact using the common subset of these 2, can we be explicit about this somehow? Since TS is structural typing only, maybe by defining an interface of the subset used? That would avoid a cast / expect-error in the place where provideWhen is used with the ERef<MapStore>.

Comment on lines 24 to 25
export * from '../nameHub.js';
export * from '../bridge.js';
Copy link
Member

Choose a reason for hiding this comment

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

These see, to be re-exporting non-type exports as well, is that intended?

If so please visually separate them. In general I prefer having runtime imports before type based ones.

Copy link
Member

Choose a reason for hiding this comment

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

I suspect the ./bridge.js import is for the BridgeManager type? In that case I believe the better approach would be to have a JSDoc @typedef in ../types.js and leverage the existing re-export from there. Same the nameHub.js's NameHub and NameAdmin.

packages/internal/src/utils.js Show resolved Hide resolved
packages/SwingSet/tools/internal-types.js Show resolved Hide resolved
packages/zoe/src/internal-types.js Show resolved Hide resolved
Comment on lines 96 to 97
// @ts-expect-error cast
E.get(homeP).scratch,
Copy link
Member

Choose a reason for hiding this comment

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

While I mentioned above I'd prefer to figure out the provideWhen's param type to the compatible subtype, is there a reason to use // @ts-expect-error for casts instead of doing an actual cast ?

Do we consider casting to be too visually onerous?

Copy link
Member Author

Choose a reason for hiding this comment

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

Moot with 570cc99, but I do find casting in JSdoc to be hard to read. No strong feeling one way or the other.

@@ -50,7 +51,7 @@ export function buildRootObject(_vatPowers) {
// Update the notifier when the chainBundle resolves.
const { notifier, updater } = makeNotifierKit();
chainBundle.then(clientHome => {
updater(harden({ clientHome, clientAddress: address }));
updater.updateState(harden({ clientHome, clientAddress: address }));
Copy link
Member

Choose a reason for hiding this comment

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

Fix LGTM, but I should probably defer to someone more familiar with this code and notifiers. I believe this is the only behavioral difference in this PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, the only intended behavior change. updater comes out of makeNotifierKit which just has updateState, fail and finish. The comment says "Update the notifier" so I'm sure it's not meant to be one of the latter two.

FYI @michaelfig who I think wrote this.

packages/vats/src/types.js Show resolved Hide resolved
packages/vats/src/core/boot.js Outdated Show resolved Hide resolved
@@ -68,7 +68,7 @@ export const reserveThenDeposit = async (
console.info('confirmed deposit for', debugName);
};

/** @type {<T>(store: ERef<Map<string, T>>, key: string, make: () => T) => Promise<T>} */
/** @type {<T>(store: ERef<Pick<MapStore<string, T>, 'get' | 'set'>>, key: string, make: () => T) => Promise<T>} */
const provideWhen = async (store, key, make) => {
const found = await E(store).get(key);
Copy link
Member

Choose a reason for hiding this comment

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

I probably should have looked at the actual implementation before.

I was under the impression that MapStore threw when doing a get of an uninitialized value. That's what I meant earlier by different semantics, unfortunately the signature of get methods only varies on the return type between Map and MapStore, making them "compatible". Thinking more about this, it's probably a footgun that these objects have such a similar shape, yet such different semantics.

Anyway, I think provideWhen is faulty because of this, and I don't understand how the fallback path would have every worked with the MapStore variant.

Copy link
Member Author

Choose a reason for hiding this comment

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

Agree with your assessment. Is there a requested change in there? An issue to make or a thread to start?

Copy link
Member

Choose a reason for hiding this comment

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

I don't know. I don't think it'd be easy enough to fix now, but at least we should create an issue?

I think reverting the Pick and adding a ts-expect-error pointing to the issue?

Copy link
Member Author

@turadg turadg Nov 1, 2022

Choose a reason for hiding this comment

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

I made an issue but then realized a simpler fix: bf9b05f

Copy link
Member

Choose a reason for hiding this comment

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

I fail to see how it's a fix?

@@ -351,7 +351,7 @@ export {};
*
* @typedef { string } BundleID
* @typedef {*} BundleCap
* @typedef { { moduleFormat: 'endoZipBase64', endoZipBase64: string, endoZipBase64Sha512 } } EndoZipBase64Bundle
* @typedef { { moduleFormat: 'endoZipBase64', endoZipBase64: string, endoZipBase64Sha512: string } } EndoZipBase64Bundle
Copy link
Member

Choose a reason for hiding this comment

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

Oh yeah that would do it!

Comment on lines +8 to +9
export * from './src/nameHub.js';
export * from './src/bridge.js';
Copy link
Member

Choose a reason for hiding this comment

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

I still believe this will cause formerly internal runtime helpers to now be visible on the root of this package, not only types.

See #6500 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the thorough review!

I suspect the ./bridge.js import is for the BridgeManager type? In that case I believe the better approach would be to have a JSDoc @typedef in ../types.js and leverage the existing re-export from there. Same the nameHub.js's NameHub and NameAdmin.

makeNameHubAdmin is imported in three other modules, so arguably this top level is an improvement, but I'll err towards conservative and leave runtime exports refactoring for another day.

@@ -108,6 +110,7 @@ export const makeInstallCache = async (
};

const wrapInstall = install => async (mPath, bPath, opts) => {
// @ts-expect-error xxx bundle types
Copy link
Member

Choose a reason for hiding this comment

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

I believe runtime changes are worth when they directly address issues found by typing. improvements

@mhofman mhofman self-requested a review November 1, 2022 14:13
@turadg turadg mentioned this pull request Nov 1, 2022
Copy link
Member

@mhofman mhofman left a comment

Choose a reason for hiding this comment

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

I'm not sure I understand how the provideWhen type change is actually a fix.

@@ -81,7 +81,7 @@ const provideWhen = async (store, key, make) => {

/**
*
* @param {{ scratch: ERef<MapStore<string, CopyTagged>> }} homeP
* @param {{ scratch: ERef<Map<string, CopyTagged>> }} homeP
Copy link
Member

Choose a reason for hiding this comment

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

Does scratch actually have Map semantics? If not that'd be a very unobvious cast that hide the runtime differences.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it does

get: async keyP => {
const key = await keyP;
return map.get(key);
},

@@ -68,7 +68,7 @@ export const reserveThenDeposit = async (
console.info('confirmed deposit for', debugName);
};

/** @type {<T>(store: ERef<Map<string, T>>, key: string, make: () => T) => Promise<T>} */
/** @type {<T>(store: ERef<Pick<MapStore<string, T>, 'get' | 'set'>>, key: string, make: () => T) => Promise<T>} */
const provideWhen = async (store, key, make) => {
const found = await E(store).get(key);
Copy link
Member

Choose a reason for hiding this comment

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

I fail to see how it's a fix?

@@ -21,9 +21,11 @@ const DEFAULT_WALKER = Far('walker', { walk: pluginRootP => pluginRootP });

/**
* @template T
* @typedef {T} Device
* @typedef {'Device' & { __deviceType__: T }} Device
Copy link
Member

Choose a reason for hiding this comment

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

🎉

Comment on lines 7 to +8
import '@agoric/swingset-vat/exported.js';
import '@agoric/swingset-vat/src/vats/network/types.js';
Copy link
Member

Choose a reason for hiding this comment

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

Seeing this now, would it make sense to add import './src/vats/network/types.js'; to @agoric/swingset-vat/exported.js instead ?

Edit: maybe not since it's used directly in other places?

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah, I considered that and opted for lesser change to what's exported. I figure it will be addressed in further ambients work

@turadg turadg force-pushed the 1254-export-types branch from bf9b05f to 078263a Compare November 1, 2022 19:29
@turadg turadg added the automerge:no-update (expert!) Automatically merge without updates label Nov 1, 2022
Copy link
Member

@mhofman mhofman left a comment

Choose a reason for hiding this comment

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

LGTM

@turadg turadg mentioned this pull request Nov 1, 2022
@mergify mergify bot merged commit aad309a into master Nov 1, 2022
@mergify mergify bot deleted the 1254-export-types branch November 1, 2022 22:21
@dckc
Copy link
Member

dckc commented Nov 2, 2022

I would have like to see more coordination around getting rid of @ts-check. It's a useful explicit tag, especially when moving code between repositories.

@turadg turadg mentioned this pull request Nov 2, 2022
@turadg
Copy link
Member Author

turadg commented Nov 2, 2022

I would have like to see more coordination around getting rid of @ts-check. It's a useful explicit tag, especially when moving code between repositories.

@dckc it's an easy change to reverse. You want every JS file in a package to have @ts-check even if it's redundant with the package configuration?

@dckc
Copy link
Member

dckc commented Nov 2, 2022

You want every JS file in a package to have @ts-check even if it's redundant with the package configuration?

That would have been my preference, yes. At this point, I don't feel strongly that it's worth more churn in the git history. But it seems like a change to house style that's worth fairly widespread coordination.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge:no-update (expert!) Automatically merge without updates
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants