-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[AST] Paren'd reference to an IUO function crashes the compiler in SILGen #26831
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
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
32a0c8e
[AST] Strip off parens around an ApplyExpr's function
theblixguy f02a5f3
[Test] Add a test case
theblixguy ff7e8b1
[CSSimplify] If we're trying to assign the result of an IUO method wr…
theblixguy 4fd2a4c
[CS] Move the check to CSGen
theblixguy 76c29af
[Test] Adds a test case
theblixguy 0660764
[CS] Move the check to resolveOverload()
theblixguy b33c520
[CS] Extract the check into a separate lambda
theblixguy 6797148
[CS] Only check for the presence of a paren expr
theblixguy 32cfd5b
[CS] Only check if the decl has a function type
theblixguy 28d0c08
[CSApply] shouldForceUnwrapResult() should return false when we don't…
theblixguy a2daa11
Merge branch 'master' into fix/SR-10492
theblixguy 532498b
[CSApply] Use the choiceLocator, not locator when checking if a disju…
theblixguy b32386b
[CS] If locator points to a function call, then compare the fn and se…
theblixguy fc9fef2
[CS] Be more defensive in isIUOWrappedInParens() check
theblixguy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2190,9 +2190,34 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, | |
openedFullType, | ||
refType}; | ||
|
||
// If we have something like '(s.foo)()', where 's.foo()' returns an IUO, | ||
// then we need to only create a single constraint that binds the | ||
// type to an optional. | ||
auto isIUOCallWrappedInParens = [&]() { | ||
auto decl = choice.getDecl(); | ||
auto type = decl ? decl->getInterfaceType() : nullptr; | ||
if (!type || !type->is<AnyFunctionType>()) | ||
return false; | ||
|
||
auto expr = locator->getAnchor(); | ||
if (!expr) | ||
return false; | ||
|
||
if (isa<CallExpr>(expr)) { | ||
return false; | ||
} | ||
|
||
auto parentExpr = getParentExpr(expr); | ||
if (parentExpr && isa<ParenExpr>(parentExpr)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if the paren isn't an immediate parent? For example, I believe we'll incorrectly allow the following to typecheck (and then crash in SILGen like example in the bug report): struct S {
func foo() -> Int! { 0 }
}
let s = S()
let x1: Int = (S.foo(s))() // Paren surrounds a parent CallExpr of a double application.
let x2: Int = (s.foo.self)()
let x3: Int = (s.foo as () -> Int)() |
||
return true; | ||
|
||
return false; | ||
}; | ||
|
||
// In some cases we already created the appropriate bind constraints. | ||
if (!bindConstraintCreated) { | ||
if (choice.isImplicitlyUnwrappedValueOrReturnValue()) { | ||
if (choice.isImplicitlyUnwrappedValueOrReturnValue() && | ||
!isIUOCallWrappedInParens()) { | ||
// Build the disjunction to attempt binding both T? and T (or | ||
// function returning T? and function returning T). | ||
buildDisjunctionForImplicitlyUnwrappedOptional(boundType, refType, | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// RUN: not %target-swift-frontend -emit-silgen %s | ||
|
||
struct S { | ||
func foo() -> Int! { return 0 } | ||
} | ||
|
||
let s = S() | ||
let x: Int = (s.foo)() |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 about
SubscriptExpr
andKeyPathExpr
anchors? I believe we'll incorrectly reject the following examples:Adding specific exceptions for these cases feels pretty brittle, perhaps we should follow a similar pattern to
markDirectCallee
where only callees that have definedsetFunctionRefKind
andgetFunctionRefKind
are considered?Though IMO that's still not an ideal solution – in the long run, if we don't make the source breaking change of having
markDirectCallee
not look through parentheses, we may want to turnFunctionRefKind
into a class and store an additional flag on it to answer the question "does this reference decay to a function value such that it doesn't produce an IUO?".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 these cases seem to be a different issue. None of the locators, associated with member overload set, in these examples are going to be anchored in
ParenExpr
. That said, I think we indeed need to come up with a better solution than what we currently have, creating new disjunctions in multiple distinct places is not robust enough.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.
@xedin Just to clarify – these are cases that compiled before this change, and no longer compile after. The parent
ParenExpr
comes from their use as arguments in a function call, so we incorrectly consider them to be "IUO calls wrapped in parens".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.
Ah, right because it's checking for parent to be a
ParentExpr
, for some reason I thought that it's checking for anchor to be a paren. Looks like we need to revert and find a better alternative.Uh oh!
There was an error while loading. Please reload this page.
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're right, those cases do not compile:
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.
So, perhaps the check could be:
Do you find anything wrong with this logic?
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.
@theblixguy One potential problem with comparing
getFn()
withgetSemanticFn()
is that they won't be equal for cases like this:which (I think?) we want to allow. In addition, they will be equal for cases like this:
which we want to reject. I think what we'll want to do is check whether there is a
ParenExpr
between the call'sgetFn()
and its "direct callee" (as determined bymarkDirectCallee
).If we turned
FunctionRefKind
into a class that stores an additional flag for "does this reference decay to a function value such that it doesn't produce an IUO?", I believe we could do this logic directly inmarkDirectCallee
by setting the flag if we had to look through a paren.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 will give that a try tomorrow 👍
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.
Sorry it took me a bit to get back to this today, just wanted to mention that I concur with what @hamishknight is proposing.
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'd reject this one myself, but also probably zero people are relying it, even more than the parentheses.