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

Refactor import resolution to use a global store #204

Merged
merged 14 commits into from
Dec 8, 2020
Merged

Conversation

Nadrieril
Copy link
Owner

@Nadrieril Nadrieril commented Dec 7, 2020

This is the first step towards concurrent/async import resolution, as needed for wasm support but also more generally would be cool.
This is an intense PR. The idea is that instead of storing the result of an import in the Hir directly, instead we store and index into a global store. Which means I had to make the global store accessible to any code that would need to read an import. I ended up adding a lot of lifetimes x).
So now import resolution runs in two phases: first traverse the ast and replace the imports by their indices, and then go through the imports and resolve them. By making that second step smaller, we'll make it possible to add async and to batch imports.

I got excited with the global store. There's a few more cool things I want to do with it. I hope this is not making the code too much more complicated.
Among other things, once non-import errors don't count for import alternatives (dhall-lang/dhall-lang#1113), we can decouple entirely import resolution from the rest of the code. That would not have been possible before this PR without introducing lots of duplicate work.

cc @basile-henry

Copy link
Collaborator

@basile-henry basile-henry left a comment

Choose a reason for hiding this comment

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

Nice work! 😄

This looks pretty involved 😅 I was wondering if it wouldn't be simpler if the global import store was kept in a global mutable data structure. You can get something pretty good with lazy_static and a Mutex. I believe this would remove the need for lifetimes everywhere, and you wouldn't have to thread the context to all the functions that need it.

About issue dhall-lang/dhall-lang#1113, while I still think it's worth thinking about whether parse errors and typecheck errors should influence alternative imports, I am now less sure that it will make things much easier for resolving imports concurrently.
After talking with @ocharles on Slack about it, it became more clear to me that typechecking still needs to be done on a per file basis, and that we cannot simply inline the result of an import into the expression where it is imported without typechecking it first. He pointed out this is particularly important when dealing with free variables resolution, where they obviously should not leak between imports. You probably already understood this, and I didn't think it through. 😅

So is the main benefit for you to have fewer files to typecheck by being able to eliminate some alternatives earlier? Even if we don't get this issue resolved, we should be able to typecheck all alternatives concurrently (which on non-wasm targets could actually be done in parallel), no?

Comment on lines +139 to +144
pub struct StoredImportAlternative<'cx> {
pub left_imports: Box<[ImportNode<'cx>]>,
pub right_imports: Box<[ImportNode<'cx>]>,
/// `true` for left, `false` for right.
selected: OnceCell<bool>,
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

How does this work? I'm not sure it can support nested alternatives, can it?

Copy link
Owner Author

Choose a reason for hiding this comment

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

It can :) An ImportNode can be either a single import or another alternative

@Nadrieril
Copy link
Owner Author

Nadrieril commented Dec 7, 2020

Yeah, I considered the global mutable store but it made me sad :(. The pain of lifetimes is mostly adding them, but once they're there they're not too painful I find.
Typechecking will still be on a per-file basis, that's not an issue. What dhall-lang/dhall-lang#1113 would give me is that none of the resolve code even needs to know that such a thing as typechecking and normalization exist. Which would be awesome. Parallel typechecking would also be possible if we want, whereas currently it would have to be entangled with import fetching and alternatives decition-making.

@Nadrieril
Copy link
Owner Author

Nadrieril commented Dec 7, 2020

EDIt: I confused myself, for a moment I thought there were no dependencies between different files when we typecheck :(
The point I wanted to make still stands though: trying to schedule parallelism for both typechecking and imports sounds harder than first doing imports and second doing typechecking (and third normalization). For example imports benefit from being batched and async but typechecking doesn't.

@Nadrieril
Copy link
Owner Author

Eh, I want to run with this and see where it leads. I think we really want some sort of store, we can always make it static later if the lifetimes-based one is too painful

@Nadrieril Nadrieril merged commit 109dcf8 into master Dec 8, 2020
@Nadrieril Nadrieril deleted the source-id branch December 8, 2020 18:47
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.

2 participants