-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Concurrency] Handle more expr types for inout checking #35325
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
[Concurrency] Handle more expr types for inout checking #35325
Conversation
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 definitely progress, and I appreciate the greater test coverage. I'm a bit nervous that we haven't handled all of the cases, but I don't have a good sense of how to ensure that we have handled all of the cases here, so +1 for progress.
lib/Sema/TypeCheckConcurrency.cpp
Outdated
if (const InOutExpr *inout = dyn_cast<InOutExpr>(currentExpr)) { | ||
return nullptr; // The AST walker will hit this again | ||
} else if (const LookupExpr *baseArg = dyn_cast<LookupExpr>(currentExpr)) { | ||
while (const LookupExpr *nextLayer = dyn_cast<LookupExpr>(baseArg->getBase())) |
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 don't think we need this loop, given that you'll go around the outer loop again anyway?
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.
Loop gone.
@swift-ci smoke test please |
@swift-ci please smoke test |
@swift-ci please smoke test windows |
@swift-ci please smoke test windows platform |
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.
Like Doug, I do wonder what other expression forms might be missing, but this is good as-is.
What happens with other kinds of operators, e.g., function application, unary negation, addition, and the conditional ternary operator ? :
? Can they be used inside of an in-out argument expression? (I don't know the normal restrictions on in-out)
I agree on the issue with other expressions. I've tested what I know how to hit and can be passed I've kind of started going through the list of From that I'm missing the following expression types (as defined in Expr.h):
I definitely need to add a clause for |
2fa34d6
to
5d59261
Compare
@swift-ci please smoke test |
5d59261
to
cb0fb34
Compare
@swift-ci please smoke test |
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.
Some feedback to help improve the implementation:
lib/Sema/TypeCheckConcurrency.cpp
Outdated
/// | ||
/// The return will either be a LookupExpr or a DeclRefExpr. | ||
/// If part of the sub-expression isn't interesting, returns nullptr | ||
static const Expr *getInoutTopExpr(const InOutExpr *arg) { |
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, instead of trying to manually enumerate all of the possible expressions that could appear, you could try using some existing infrastructure that can handle some or all of those cases for you in this search for a DeclRef
.
For example, we have Expr::getReferencedDecl
which appears to do something similar to your getInoutTopExpr
function. A key thing to note is that getReferencedDecl
would return the referenced member, and not the base, of a LookupExpr
(see the cases for MemberRef
, as an example). I don't think that difference would limit you from using it in some capacity, though. (for example, you could determine the base Decl from the member Decl returned, or if that doesn't work, use both getReferencedDecl
and your own search loop)
There's also Expr::forEachChildExpr
which one could use to do a generic walk over the whole expression tree though perhaps that's a bit much?
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.
Okay, I've switched it to using expr::forEachChildExpr
. Still a little nervous that it might accept invalid code.
Not a huge fan of the double-lambdas, but it should do the right things.
@swift-ci please smoke test |
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 this version is quite clean now. 👍🏼
We were handling weren't handling all of the expression types that can show up as part of a parameter. As a result, the compiler was crashing on correct code. This patch introduces handling for far more expression types and the appropriate tests for each. Added handling includes: - Gentle optional unwrap - Forceful optional unwrap - Identity expressions (await, parens, etc) - Implicit conversion exprs
Fixing merge conflicts, then merging. Thanks for the reviews. |
Replacing ad-hoc expression tree with forEachChild traversal and matching the desired expression. This should avoid crashes, but may accept invalid code in the future.
447ff4a
to
3a3aaf1
Compare
@swift-ci please test |
This patch fixes a compiler crash when optional values were being unwrapped and passed to a function. The crash was caused because
diagnoseInOutArg
could only handleLookupExpr
andDeclRefExpr
. This patch adds code to unwrap more kinds of expressions.I've introduced a new static function,
getInoutTopExpr
, which walks through the expression types it knows about down to what is hopefully either aLookupExpr
or aDeclRefExpr
, from which we can pull the correctValueDecl
.If we hit an
InOutExpr
sub-expression while traversing, we just return a nullptr and jump out of the diagnostic. If we don't do this, we will get duplicate error messages emitted since it appears to get re-checked. The duplicate error messages show up onawait modifyAsynchronously(&points[0].x)
andawait modifyAsynchronously(&points[0].z!)
.Fixes: rdar://72906215