Skip to content

Fix #11464: avoid expanding local paramRef in HKTypeLambda #11465

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

Merged
merged 3 commits into from
Mar 2, 2021

Conversation

liufengyun
Copy link
Contributor

@liufengyun liufengyun commented Feb 18, 2021

Fix #11464: avoid expanding local paramRef in HKTypeLambda

@smarter
Copy link
Member

smarter commented Feb 18, 2021

Could you try re-enabling scissLucre in the community build? It was disabled a few months ago due to an unrelated problem in the community build (#10828 (comment)), and it fails on master with the Range ClassCastException

@liufengyun
Copy link
Contributor Author

test performance please

@dottybot
Copy link
Member

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

@dottybot
Copy link
Member

Performance test finished successfully:

Visit http://dotty-bench.epfl.ch/11465/ to see the changes.

Benchmarks is based on merging with master (9254ef6)

emptyRange
if variance == 1 then defn.AnyType
else if variance == -1 then defn.NothingType
else TypeBounds.empty
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is still not correct conceptually -- we need to know both the kind and variance of the LazyRef in order to produce an approximation.

@liufengyun liufengyun self-assigned this Feb 19, 2021
@liufengyun
Copy link
Contributor Author

test performance please

@dottybot
Copy link
Member

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

@dottybot
Copy link
Member

Performance test finished successfully:

Visit http://dotty-bench.epfl.ch/11465/ to see the changes.

Benchmarks is based on merging with master (aa7c21e)

@liufengyun liufengyun requested a review from smarter February 23, 2021 09:52
@@ -5724,6 +5724,37 @@ object Types {
foldOver(xs, tp)
end NamedPartsAccumulator

class ExistsLocalRef(using Context) extends TypeAccumulator[Boolean]:
Copy link
Member

Choose a reason for hiding this comment

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

Does this actually make type avoidance faster? It's not clear to me because this still requires traversing the type to see if there's something to avoid.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't have much empirical evidence. It avoids computing localSyms and it has shortcut for references to type or term parameters. Or we can enhance the TypeOps.avoid. This part can come later if there indeed a noticeable speedup. For now, I'll remove it from the PR.

@liufengyun
Copy link
Contributor Author

test performance please

@dottybot
Copy link
Member

dottybot commented Mar 2, 2021

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

@dottybot
Copy link
Member

dottybot commented Mar 2, 2021

Performance test finished successfully:

Visit http://dotty-bench.epfl.ch/11465/ to see the changes.

Benchmarks is based on merging with master (1dc4894)

Avoid unnecessary recursive types in the presence of LazyRef.
@liufengyun liufengyun changed the title Fix #11464: avoid leaking Range Fix #11464: avoid expanding local paramRef in HKTypeLambda Mar 2, 2021
@liufengyun liufengyun requested a review from smarter March 2, 2021 14:26
Comment on lines 432 to 434
case tp: ThisType if toAvoid(tp.cls) =>
range(defn.NothingType, apply(classBound(tp.cls.classInfo)))
case tp: ThisType =>
tp
Copy link
Member

Choose a reason for hiding this comment

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

Could you explain why this change is needed and why it's safe to not do avoidance here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't need this, this is an optimization -- the rationale is that ThisType doesn't exist outside of class, thus they are always safe in avoidance.

Copy link
Member

Choose a reason for hiding this comment

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

OK, I think this makes sense but it'd be good to check with an assert that this never happens in our tests (once the tests pass we can disable the assert for performance), and to add a comment explaining that this is safe.

Comment on lines 432 to 434
case tp: ThisType if toAvoid(tp.cls) =>
range(defn.NothingType, apply(classBound(tp.cls.classInfo)))
case tp: ThisType =>
tp
Copy link
Member

Choose a reason for hiding this comment

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

OK, I think this makes sense but it'd be good to check with an assert that this never happens in our tests (once the tests pass we can disable the assert for performance), and to add a comment explaining that this is safe.

case tp: LazyRef if isExpandingBounds =>
emptyRange
case tp: LazyRef =>
if locals.contains(tp.ref) then tp
Copy link
Member

Choose a reason for hiding this comment

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

Why is it safe to return tp here, doesn't it need to be avoided if it contains a local symbol?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here locals mean locally bound ParamRef in a HKTypeLambda -- we remember that in the set locals. The set is not the set of local symbols to be avoided.

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 see, would be good to give it another name to avoid confusing it with localSyms I think :). Maybe localParamRefs ?

@@ -401,6 +401,7 @@ object TypeOps:
def avoid(tp: Type, symsToAvoid: => List[Symbol])(using Context): Type = {
val widenMap = new ApproximatingTypeMap {
@threadUnsafe lazy val forbidden = symsToAvoid.toSet
val locals = util.HashSet[Type]()
Copy link
Member

Choose a reason for hiding this comment

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

As an optimization, this could be an uninitialized var which is only initialized the first time we encounter an HKTypeLambda.

Copy link
Member

Choose a reason for hiding this comment

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

(or just make it a lazy val).

@liufengyun
Copy link
Contributor Author

OK, I think this makes sense but it'd be good to check with an assert that this never happens in our tests (once the tests pass we can disable the assert for performance), and to add a comment explaining that this is safe.

@smarter Could you elaborate a little bit about the assertion? To clarify, ThisType of course can occur in avoidance, but they are safe because the ThisType must be a class that encloses the block to be avoided.

@smarter
Copy link
Member

smarter commented Mar 2, 2021

What I had in mind was to add an assert(!toAvoid(tp.cls)) in the ThisType clause to verify that indeed we don't have any ThisType to avoid.

// ThisType is only used inside a class.
// Therefore, either they don't appear in the type to be avoided, or
// it must be a class that encloses the block whose type is to be avoided.
assert(!toAvoid(tp.cls))
tp
Copy link
Contributor Author

@liufengyun liufengyun Mar 2, 2021

Choose a reason for hiding this comment

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

@liufengyun liufengyun merged commit d7bbdcd into scala:master Mar 2, 2021
@liufengyun liufengyun deleted the fix-11464 branch March 2, 2021 20:14
@Kordyjan Kordyjan added this to the 3.0.0 milestone Aug 2, 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
4 participants