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

Make incremental compilation aware of synthesized mirrors #18310

Merged
merged 3 commits into from
Jul 31, 2023

Conversation

smarter
Copy link
Member

@smarter smarter commented Jul 29, 2023

A product mirror needs to be resynthesized if any class parameter changes, and
a sum mirror needs to be resynthesized if any child of the sealed type changes,
but previously this did not reliably work because the dependency recording in
ExtractDependencies was unaware of mirrors.

Instead of making ExtractDependencies aware of mirrors, we solve this by
directly recording the dependencies when the mirror is synthesized, this way we
can be sure to always correctly invalidate users of mirrors, even if the
synthesized mirror type is not present in the AST at phase ExtractDependencies.

This is the first time that we record dependencies outside of the
ExtractDependencies phase, in the future we should see if we can extend this
mechanism to record more dependencies during typechecking to make incremental
compilation more robust (e.g. by keeping track of symbols looked up by macros).

Eventually, we might even want to completely get rid of the ExtractDependencies
phase and record all dependencies on the fly if it turns out to be faster.

This will be used later in this PR to perform dependency recording during
Typer.

The new API is slightly higher level:
- Dependencies are recorded using `addUsedName`, `addUsedRawName` and `addClassDependency`.
- `addUsedName` takes a Symbol instead of a Name and takes care of name
  mangling, `addUsedRawName` is still available when there is no
  symbol (currently this only happens when recording a dependency on a renamed import).
- These methods do not take a `from` argument, instead they take care of
  calling `resolveDependencySource` internally.
- Recorded dependencies are sent to Zinc using `sendToZinc`.
This option is meant to avoid overcompilation involving sealed classes. By
default, Zinc invalidates all usages of a sealed class when a child is added or
removed, even though `val x: Sealed = new Child1` will work the same if
`Sealed` gets an extra child. When this option is on, Zinc only takes children
into account if the name usage is reported with `UseScope.PatMatTarget`. Note
that currently this is only set when traversing the scrutinee of a pattern
match (just like in the Scala 2 implementation), but to safely turn this option
on by default we would need to kept track of all call to `children` and
`sealedDescendants` in the compiler.

There were two issues related to this option before this commit:
- ExtractAPI was unnecessarily extracting the `@Child`
  annotation, so the API hash of a sealed class changed even with
  `useOptimizedSealed` enabled.
- When registering a used name with `UseScope.PatMatTarget` we should also
  register it with `UseScope.Default` because (part of) the scrutinee type
  might not be a sealed class, in which case it won't have
  a name hash for PatMatTarget but should still lead to invalidations.

Since we only ever use two values for the `UseScope` parameter of the
`usedName` callback, we create two vals `DefaultScopes` and `PatMatScopes` that
we reuse for performance.
@smarter
Copy link
Member Author

smarter commented Jul 29, 2023

test performance with #sbt please: 1dc9761 3a2141b

@dottybot
Copy link
Member

performance test scheduled for 1dc9761 3a2141b: 132 job(s) in queue, 1 running.

A product mirror needs to be resynthesized if any class parameter changes, and
a sum mirror needs to be resynthesized if any child of the sealed type changes,
but previously this did not reliably work because the dependency recording in
ExtractDependencies was unaware of mirrors.

Instead of making ExtractDependencies aware of mirrors, we solve this by
directly recording the dependencies when the mirror is synthesized, this way we
can be sure to always correctly invalidate users of mirrors, even if the
synthesized mirror type is not present in the AST at phase ExtractDependencies.

This is the first time that we record dependencies outside of the
ExtractDependencies phase, in the future we should see if we can extend this
mechanism to record more dependencies during typechecking to make incremental
compilation more robust (e.g. by keeping track of symbols looked up by macros).

Eventually, we might even want to completely get rid of the ExtractDependencies
phase and record all dependencies on the fly if it turns out to be faster.
@smarter
Copy link
Member Author

smarter commented Jul 29, 2023

test performance with #sbt please: 1dc9761 ec59c31

@dottybot
Copy link
Member

performance test scheduled for 1dc9761 ec59c31: 132 job(s) in queue, 1 running.

@smarter smarter linked an issue Jul 29, 2023 that may be closed by this pull request
@smarter smarter requested a review from bishabosha July 29, 2023 20:58
@dottybot
Copy link
Member

Performance test finished successfully:

Visit https://dotty-bench.epfl.ch/18310/ to see the changes.

Benchmarks is based on merging with main (a73316a)

@smarter smarter added the backport:nominated If we agree to backport this PR, replace this tag with "backport:accepted", otherwise delete it. label Jul 31, 2023
if (includeSealedChildren)
_names(name) = PatMatScopes
else
_names.getOrElseUpdate(name, DefaultScopes)
Copy link
Member

Choose a reason for hiding this comment

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

is this going to reuse the closure?

Copy link
Member Author

Choose a reason for hiding this comment

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

The by-name closure isn't guaranteed to be reused, it's up to the JVM

@bishabosha bishabosha self-requested a review July 31, 2023 12:36
@bishabosha bishabosha merged commit 082dc6f into scala:main Jul 31, 2023
17 checks passed
@bishabosha bishabosha deleted the zinc-mirror-2 branch July 31, 2023 12:37
@Kordyjan Kordyjan removed the backport:nominated If we agree to backport this PR, replace this tag with "backport:accepted", otherwise delete it. label Oct 10, 2023
@Kordyjan
Copy link
Contributor

Kordyjan commented Dec 1, 2023

@bishabosha, I think it requires #17594 for backporting. Is that right?

@bishabosha
Copy link
Member

bishabosha commented Dec 1, 2023

@bishabosha, I think it requires #17594 for backporting. Is that right?

yes, at least it is using the resolveSibling definition in AbstractFile, added in that PR

@Kordyjan Kordyjan added this to the 3.4.0 milestone Dec 20, 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.

Incremental Compilation inconsistent
4 participants