-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Conversation
Could you try re-enabling |
test performance please |
performance test scheduled: 1 job(s) in queue, 0 running. |
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 |
There was a problem hiding this comment.
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.
test performance please |
performance test scheduled: 1 job(s) in queue, 0 running. |
Performance test finished successfully: Visit http://dotty-bench.epfl.ch/11465/ to see the changes. Benchmarks is based on merging with master (aa7c21e) |
@@ -5724,6 +5724,37 @@ object Types { | |||
foldOver(xs, tp) | |||
end NamedPartsAccumulator | |||
|
|||
class ExistsLocalRef(using Context) extends TypeAccumulator[Boolean]: |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
test performance please |
performance test scheduled: 1 job(s) in queue, 0 running. |
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.
case tp: ThisType if toAvoid(tp.cls) => | ||
range(defn.NothingType, apply(classBound(tp.cls.classInfo))) | ||
case tp: ThisType => | ||
tp |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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: ThisType if toAvoid(tp.cls) => | ||
range(defn.NothingType, apply(classBound(tp.cls.classInfo))) | ||
case tp: ThisType => | ||
tp |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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]() |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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).
@smarter Could you elaborate a little bit about the assertion? To clarify, |
What I had in mind was to add an |
// 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@smarter The CI confirmed the assertion. See https://github.com/lampepfl/dotty/actions/runs/614834038
Fix #11464: avoid expanding local paramRef in HKTypeLambda