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

Optimize lub algorithm #20034

Merged
merged 4 commits into from Mar 29, 2024
Merged

Optimize lub algorithm #20034

merged 4 commits into from Mar 29, 2024

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Mar 27, 2024

Replace mergeIfSuper by a different algorithm that is more efficient.
We drop or-summands in both arguments of a lub that are subsumed by the other.
This avoids expensive recursive calls to lub or expensive comparisons
with union types on the right.

I tested the previous performance regression #19907 with the new algorithm, and without the changes in #19995 that avoid a slow lub. Where previously it took minutes it now compiles fast.

Specifically, we get for i19907_slow_1000_3.scala: 2.9s with the optimizations in #19995, 3.3s with just this PR. And for i19907_slow_1000_4.scala: 3.9s with the optimizations in #19995, 4.5s with just this PR. So the optimizations in #19995 are much less critical now since lubs are much faster. Still, it's probably worthwhile to leave them in in case there is a humongous program that stresses lubs even more.

Simplify had some elaborate condition that prevented hard union types to be
recomputed with a lub. I am not sure why that was. In the concrete scenario
of i10693.scala, we had an explicitly union result type `B | A` where `A` and `B` are
type parameters. So that is a hard union type. Then `A` was instantiated by `Int | String`
and `B` was instantiated by `String | Int`. Re-forming the lub of that union would
have eliminated one pair, but since the union type was hard tyat was not done. On the
other hand I see no reason why hard unions should not be re-lubbed. Hard unions are
about preventing the widening of or types with a join. I don't see a connection with
avoiding re-lubbing.

Fixes scala#10693
Replace mergeIfSuper by a different algorithm that is more efficient.
We drop or-summands in both arguments of a lub that are subsumed by the other.
This avoids expesnive recusive calls to lub or expensive comparisons
with union types on the right.
@odersky
Copy link
Contributor Author

odersky commented Mar 27, 2024

Based on #20027. Last commit is new.

@@ -157,15 +157,8 @@ object TypeOps:
tp.derivedAlias(simplify(tp.alias, theMap))
case AndType(l, r) if !ctx.mode.is(Mode.Type) =>
simplify(l, theMap) & simplify(r, theMap)

Choose a reason for hiding this comment

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

Should this be calling into TypeComparer.glb It just seems odd to be altering the Or case, but not the And case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

& and glb are in fact the same. It's just for lub that we need the additional isSoft parameter.

case _ =>
NoType
}
private def dropIfSub(tp: Type, sup: Type, canConstrain: Boolean): Type =
Copy link
Member

Choose a reason for hiding this comment

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

The new operations are much clearer than the original mergeIfs. 👍🏼

@noti0na1
Copy link
Member

test performance please

@dottybot
Copy link
Member

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

@dottybot
Copy link
Member

Performance test finished successfully:

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

Benchmarks is based on merging with main (43ed9fd)

Copy link
Member

@noti0na1 noti0na1 left a comment

Choose a reason for hiding this comment

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

Very nice simplification, LGTM.

case _ =>
NoType
}
private def dropIfSub(tp: Type, sup: Type, canConstrain: Boolean): Type =
Copy link
Member

Choose a reason for hiding this comment

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

Add a comment:

/** If some (|-operand of) `tp` is a subtype of `sup` replace it with `NoType`. */

@odersky odersky merged commit 1aba790 into scala:main Mar 29, 2024
19 checks passed
@odersky odersky deleted the opt-lubs branch March 29, 2024 09:40
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.

None yet

4 participants