-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Rust: Data flow through overloaded operators #19685
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
Rust: Data flow through overloaded operators #19685
Conversation
7947dbf
to
0953436
Compare
0953436
to
c8746ba
Compare
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.
Overall LGTM; mostly a question about whether to use codegen for the new Call
class. PR also needs to be rebased to resolve merge conflict.
* | ||
* This class abstract over the different ways in which a function can be called in Rust. | ||
*/ | ||
abstract class Call extends ExprImpl::Expr { |
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.
I wonder if this class should instead be added via annotations.py
and suitable replace_bases
?
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.
It seems to me that it would make sense to try an merge Call
and CallExprBase
into one class. But that will require adapting a lot of places, so I think it makes sense to defer that to a follow up PR.
|
||
override Declaration getTarget() { | ||
result = inferMethodCallTarget(this) // mutual recursion; resolving method calls requires resolving types and vice versa | ||
result = CallExprImpl::getResolvedFunction(this) | ||
} | ||
} | ||
|
||
predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos) { | ||
apos.isSelf() and |
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.
The body of this predicate can now simply be apos = dpos
.
4d73871
to
5bdf989
Compare
The slowdown seems to be fixed in the most recent DCA run. |
) { | ||
if apos.isSelf() | ||
if apos.isSelf() and a.receiverImplicitlyBorrowed() |
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.
I'm not too fond of having a
in adjustAccessType
, it should be sufficient to know the position and not the actual access. That would require changing TDeclarationPosition
and TAccessPosition
back to how they were, which I also prefer anyway (that makes positions a purely syntactic property).
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.
What are the downside of having a
in adjustAccessType
? Given that they're all in the bindingset
I thought it wouldn't make a difference?
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.
You are right that it doesn't matter performance-wise, I just prefer the the simpler interface, which forces type-adjustment to be a property of the position alone.
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'll make it more as before then. It just requires more boiler plate which I don't think is super nice.
c749269
to
436961f
Compare
For instance the binary `&` is overloadable but the prefix `&` is not. Similarly, `*` has a different target depending on if it's prefix or infix.
The exact same problem occurs in Ruby, hence the `multipleArgumentCallExclude` implementation is adapted from Ruby's.
436961f
to
8cde1ee
Compare
@@ -829,7 +767,7 @@ private Type inferCallExprBaseType(AstNode n, TypePath path) { | |||
n = a.getNodeAt(apos) and | |||
result = CallExprBaseMatching::inferAccessType(a, apos, path0) | |||
| | |||
if apos.isSelf() | |||
if apos.isSelf(_) |
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.
Shouldn't this be true
?
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.
I thought so as well, but for some reason it didn't work for operator calls. Extra &
types where inferred around operator calls so I left it at _
which preserves type inference as it was.
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.
I think it would make sense to investigate this further in follow up work.
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.
LGTM, some final questions.
@@ -0,0 +1,7 @@ | |||
/** | |||
* Call. |
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.
Not the most usable QL doc ;-)
/** | ||
* An expression that calls a function. | ||
* | ||
* This class abstract over the different ways in which a function can be called in Rust. |
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.
abstracts
* This class abstract over the different ways in which a function can be called in Rust. | ||
*/ | ||
abstract class Call extends ExprImpl::Expr { | ||
Call() { this.fromSource() } |
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.
Which calls happen in non-source code?
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, no. That was for debugging.
Latest DCA run looks fine. The improvement to missing call targets is now more pronounced after the |
This PR adds data flow through (simple) overloaded operators.
It does this by:
Call
class that abstracts away the different ways in which a call can occur.Call
in type inference which chops down some LOCs.Call
in data flow which then causes overloaded operators to be handled as calls.Future work:
+=
and the deref operator). In the tests writing out the desugaring doesn't work either, which seem to indicate this is blocked on other missing features in data flow.Call
withCallExprBase
. That seems doable but also has larger ramifications.