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

Streamline tryNormalize with underlyingMatchType #20268

Merged
merged 10 commits into from
Jul 5, 2024

Conversation

EugeneFlesselle
Copy link
Contributor

@EugeneFlesselle EugeneFlesselle commented Apr 25, 2024

Based on #20257

This PR has multiple small but significant changes to tryNormalize, I would recommend reviewing the commits individually.
The overall goal was to have a more uniform treatment of tryNormalize rather than the three overrides, making the logic easier to follow.

It also now reuses underlyingMatchType for it, which not only has a caching benefit but also ensures consistent results between them. In particular, making tryNormalize.exists imply underlyingMatchType.exists, which one might assume as true but did not hold in general previously. And yet, we use isMatchAlias := underlyingMatchType.exists in a bunch of places with the assumption that there is nothing to normalise if it returns false.

The next step will be to rework the MatchTypeTrace, which still overlooks some cases. But doing so should be simpler from the proposed setup.

@EugeneFlesselle EugeneFlesselle changed the title [WIP] Streamline tryNormalize with underlyingMatchType Streamline tryNormalize with underlyingMatchType Apr 25, 2024
Copy link
Contributor

@odersky odersky left a comment

Choose a reason for hiding this comment

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

Looks good to me. Let's just run a performance test to make sure there is no regression.

@odersky
Copy link
Contributor

odersky commented Apr 26, 2024

Test performance please

@EugeneFlesselle
Copy link
Contributor Author

@sjrd this still depends on eef62f7

@mbovel
Copy link
Member

mbovel commented Apr 26, 2024

test performance please

@dottybot
Copy link
Member

performance test scheduled: 3 job(s) in queue, 1 running.

@scala scala deleted a comment from dottybot Apr 26, 2024
@scala scala deleted a comment from dottybot Apr 26, 2024
@dwijnand
Copy link
Member

In particular, making tryNormalize.exists imply underlyingMatchType.exists, which one might assume as true but did not hold in general previously.

I don't understand this premise, seeing as there's more than match types involved in normalizing: constant folds.

@EugeneFlesselle
Copy link
Contributor Author

EugeneFlesselle commented Apr 26, 2024

I don't understand this premise, seeing as there's more than match types involved in normalizing: constant folds.

Yes indeed, that's my point. Even though it is not inherently wrong, it is another discrepancy which makes them harder to work with than necessary. It's also certainly not obvious for someone unfamiliar with match types who's adding an isMatchAlias guard.

reduced.normalized
catch
case ex: Throwable =>
handleRecursive("normalizing", s"${scrutinee.show} match ..." , ex)
Copy link
Member

Choose a reason for hiding this comment

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

Now that you've put back constant folding, we should probably keep the handleRecursive. Or, even better, put one in tryCompiletimeConstantFold.

@dottybot
Copy link
Member

Performance test finished successfully:

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

Benchmarks is based on merging with main (79500f7)

@odersky
Copy link
Contributor

odersky commented Apr 26, 2024

test performance please

@dottybot
Copy link
Member

performance test scheduled: 1 job(s) in queue, 0 running.

@scala scala deleted a comment from dottybot Apr 26, 2024
@scala scala deleted a comment from dottybot Apr 26, 2024
@scala scala deleted a comment from dottybot Apr 26, 2024
@scala scala deleted a comment from dottybot Apr 26, 2024
@scala scala deleted a comment from dottybot Apr 26, 2024
@scala scala deleted a comment from dottybot Apr 26, 2024
@scala scala deleted a comment from dottybot Apr 26, 2024
@scala scala deleted a comment from dottybot Apr 26, 2024
@scala scala deleted a comment from dottybot Apr 26, 2024
@scala scala deleted a comment from dottybot Apr 26, 2024
@scala scala deleted a comment from dottybot Apr 26, 2024
@dwijnand
Copy link
Member

Yes indeed, that's my point. Even though it is not inherently wrong, it is another discrepancy which makes them harder to work with than necessary. It's also certainly not obvious for someone unfamiliar with match types who's adding an isMatchAlias guard.

I don't event think it makes sense to call it a discrepancy, one is related to a subset of the other.

But I'm not against improving things or just straight changing them under some vision on how we should do things, but it's useful to understand the motivating reasons (and verify those reasons).

Also, on the overriding methods things, one reason is to cache things on private vars of the subclass, but I also think there might be some minutiae performance reasons, where using virtual method dispatch is faster and/or works better with the JIT, compared to a pattern match approach. Unlikely to be crucial here, but other times might be the reason for the setup.

@dottybot
Copy link
Member

Performance test finished successfully:

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

Benchmarks is based on merging with main (8825b07)

@EugeneFlesselle EugeneFlesselle force-pushed the match-types-tryNormalize branch from 49ddc83 to 70326f2 Compare May 6, 2024 11:04
@EugeneFlesselle
Copy link
Contributor Author

I disabled i974 from the best-effort-pickling tests, at least to test if it is the only failing case.

I'm not sure how the --Ybest-effort affects things here, but I saw there are already a few blacklisted tests. @jchyb any idea what might be happening ?

The error appears starting from 94a7765, I suspect it has to do with the stripping of a LazyRef which did not happen before.

@jchyb
Copy link
Contributor

jchyb commented May 7, 2024

In -Ybest-effort we try to pickle and unpickle the erroring trees after typer, so it makes sense that a slightly different tree returned after typer could cause issues (usually with correct programs we know what we are going to pickle, with incorrect not really, especially that we are skipping PostTyper). With that said here in a weird way it makes more sense for it to fail, since there are those other issues with cyclic references that fail.

As a rule of thumb I would not want to stop any progress in the compiler (which is more important than best-effort), which is part of why the blacklist is there. Please use it whenever you need to and do not worry about it! The important part for me is not to change the code gated by stuff like ctx.isBestEffort

EugeneFlesselle added a commit that referenced this pull request Jun 7, 2024
#20527)

It solves some stale caching issues with `AppliedType#superType` encountered in `neg/typeclass-encoding3` and when introducing more caching for match types in #20268.
These were caused by the fact that `appliedTo` may perform eta-reduction leading to different variance annotations depending on the instantiation of type params.

There seems to be no significant performance impact from the reduced opportunities for caching.
@EugeneFlesselle EugeneFlesselle force-pushed the match-types-tryNormalize branch from 70326f2 to 05831d1 Compare June 11, 2024 13:34
Delay their normalization until it is needed.
Avoids overflows from infinite match types that did not need to normalize.
Also improves MatchTypeTraces as a side effect.

It appears to have been added to avoid some separate issue, which seems to have been fixed.
It is no longer needed since the previous fix with constant folding in disjointnessBoundary.
Also fixes underlyingMatchType to not use the resType of HKTypeLambdas
It should only be in `isMatch` used for `AliasingBounds`, not `isMatchAlias`
There is already a `handleRecursive` in `reduced`
Having the two makes error messages undeterministic, see scala#20269
tryNormalize used to not recursively check if tycon of applied type was normalizable,
this may be necessary in the case of an applied type dealiasing to a type lambda.

Fixes scala#20482
@EugeneFlesselle
Copy link
Contributor Author

As a rule of thumb I would not want to stop any progress in the compiler (which is more important than best-effort), which is part of why the blacklist is there. Please use it whenever you need to and do not worry about it! The important part for me is not to change the code gated by stuff like ctx.isBestEffort

Sounds good, thanks for the detailed explanations Jan.

@EugeneFlesselle EugeneFlesselle force-pushed the match-types-tryNormalize branch from 05831d1 to 1bfa819 Compare June 28, 2024 12:43
@EugeneFlesselle
Copy link
Contributor Author

@dwijnand I know the related changes/comments have been on varying places, sorry about that. Everything should be up to date and rebased on this PR. Do you think it would worth going back to an overloading setup here regarding performance, or have other concerns with the changes ?

@EugeneFlesselle EugeneFlesselle requested a review from dwijnand June 28, 2024 12:47
@EugeneFlesselle EugeneFlesselle merged commit ab48a55 into scala:main Jul 5, 2024
24 checks passed
@EugeneFlesselle EugeneFlesselle deleted the match-types-tryNormalize branch July 5, 2024 15:39
WojciechMazur added a commit that referenced this pull request Aug 27, 2024
…5.2 (#21449)

Backports #20268 to the 3.5.2 branch.

PR submitted by the release tooling.
[skip ci]
@WojciechMazur WojciechMazur added this to the 3.5.2 milestone Oct 8, 2024
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.

Regression in Scala 3.5.0-RC1 related to implicit search and match types that return type lambdas
7 participants