-
Notifications
You must be signed in to change notification settings - Fork 10.3k
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
[SR-12723][Sema] Validate function type param representations thick-to-thin conversions #31814
[SR-12723][Sema] Validate function type param representations thick-to-thin conversions #31814
Conversation
lib/Sema/CSSimplify.cpp
Outdated
@@ -1358,10 +1359,10 @@ static bool matchFunctionRepresentations(FunctionTypeRepresentation rep1, | |||
case ConstraintKind::BindParam: | |||
case ConstraintKind::BindToPointerType: | |||
case ConstraintKind::Equal: | |||
return rep1 != rep2; | |||
case ConstraintKind::Subtype: |
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 the reason why it's done like that is because there is a subtyping rule between some of the representations which is verified/maintained by SIL, is that right @slavapestov? I guess if we wanted to change status quo here we might add actual checks whether there is a subtyping rule between given two function representations and if not - add a tailored fix.
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.
Humm, interesting ... I thought that maybe could be a rule of something like this, but I did a test on this example changing c
convention to all others and thin, block, swift
and except when the representation was the same all crashed, so my guess was that it only allowed this way... I don't understand much about SIL or how it verifies this but let me try to take a look
Thanks @xedin :)
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.
To be honest I don't know that the subtype matrix here is e.g.
func foo(_: (@convention(c) () -> Void) -> Void) {}
func bar(_: () -> Void) {}
foo(bar)
It's accepted by type-checker but crashes with assert in SILGen. Looks like CSApply generates a conversion between () -> Void
and @conversion(c) () -> Void
. Maybe we should reject this code in Sema. @jckarter, thoughts?
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.
Seems like the same happens with block
convention too, thin
doesn't.
For what I could see on SIL(although I don't understand much) is that SIL representations thin -> thick are conversions are allowed, but only in some situations ...
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.
Right, I think I'm having progress, but question... if a function foo
type has as parameter a @convetion(c)
function type which makes its representation c
, the representation of the function foo
should still be swift?
@xedin @slavapestov @jckarter
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.
@jckarter Just to clarify what you are saying is that we should forbid any conversions between different representations when function types are embedded into other type e.g. optional, argument/result of a function, generic arguments?
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 If it works today, I would still allow it for conversions from "thin" conventions (c, thin) to "thick" (swift, block) or conversions between thick conventions. It's only thick-to-thin conversions that can't be supported (except for the limited cases where we can tell that they statically reference a global function that doesn't require context).
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.
Thank you for clarification! I think we can use locator in matchFunctionTypes
to find where function type is inner and reject certain conversions in Sema.
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 get back to this later today after work :)
Just to clarify, sorry I don't know if I fully understand the "except for the limited cases where we can tell that they statically reference a global function that doesn't require context" but from what I get here is we are forbidding different representations checking for only argument locator function types?
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 I've made some changes, let me know what you think :)
c353d28
to
767a860
Compare
3ef6321
to
aae4984
Compare
@LucianoPAlmeida This should be detected in Sema in matchFunctionTypes(); SILGen is too late, because then it cannot influence overload resolution, etc. @xedin Can help you find the right place to add the checks. |
aae4984
to
0ff01e1
Compare
Right, @slavapestov that was actually the first approach when I send the PR, but the bigger question was what kind of conversion matrix actually crashes the compiler in the argument context but should be validated(because it is truly not convertible) or if although it crashes the conversion should be supported (so we can't really validate at this level)? :) |
I'm back working on this, but I have a couple of questions
struct SR12723_C {
let function: (@convention(block)() -> Void) -> Void
}
let block = SR12723_C { app in app() } // app () -> () 0x00000001000018f0 Test`partial apply forwarder for reabstraction thunk helper from @convention(thin) @convention(c) () -> () to @escaping @callee_unowned @convention(block) () -> () at <compiler-generated>
let f: (@convention(c)() -> Void) -> Void = block.function
f({ print("a") }) Should this case be supported? cc @xedin @slavapestov @jckarter :) |
ebac5b3
to
30a499b
Compare
30a499b
to
f55cb4f
Compare
589940f
to
cfdb14e
Compare
cfdb14e
to
2dec7c5
Compare
let _ : (@convention(thin) () -> Void) -> Void = c.function | ||
// expected-error@-1 {{cannot convert value of type '(@convention(c) () -> Void) -> Void' to specified type '(@convention(thin) () -> Void) -> Void'}} | ||
|
||
let _ : (() -> Void) -> Void = c.function |
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 and some other conversions here are thin-to-thick
which should be allowed. I think this is actually meant to work in reverse - thin-to-thick
is allowed but thick-to-thin
isn't.
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.
At least this is what Joe mentioned in his comment.
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.
Hey @xedin :)
Hum, that's actually one of the questions I had, because on the param function type there is the fact that subtype relation is contravariant. So my question is if this affects the conversion in some way?
In this case, for example, converting (@convention(c)()->Void)->Void
to (()->Void)->Void
on A -> B
to A'-> B'
respectivelly, this means the subtype relation is A'
is subtype of A
so the ()->Void
is a subtype of @convention(c)()->Void
, does this means the conversion is thick-to-thin
? ... at the time this makes sense to me, but that is actually a question I have, do you know if this makes sense or am I missing something? Let me know if I this makes sense :)
Also, the logic on matchFunctionTypes
is only allowing exactly thin-to-thick
and thick-to-thick
any other conversions are being deferred to check if representations are the same.
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.
Yes, you are correct, sorry for the confusion. I was just merely trying to point out that we might want to change diagnostic or add a custom note which explains precisely why these types couldn't be converted (related to contravariance) because it appears that it's passing thick-to-thin
.
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 got tripped by this myself because I didn't notice that diagnostic mentioned whole function 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.
Right, thanks for the clarification :)
I've added in the last commit, thin to thin which seems to be allowed, so now we strictly only validating thick-to-thin
.
we might want to change diagnostic or add a custom note which explains precisely why these types couldn't be converted (related to contravariance) because it appears that it's passing
About the note, I think it makes sense, but I'm not sure how to phrase it because I'm not sure if we should mention variance, or only mention that the representations are not convertible in a parameter subtype context ...
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.
Yeah, it's a good question how note should be worded exactly...
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.
After thinking about this some more - I think we should just open a follow up SR for the note and merge what we have now.
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 makes sense :)
d727d89
to
fab5a46
Compare
@swift-ci please test |
Source compatibily bot is having a bad day but we should run it before merging. |
Build failed |
Right 👍 Seems like there are some issues with the CI in general lately, Linux bots were consistently failing in some PRs |
Build failed |
…k to thin and thick to thick representations on subtype context
…rtain representation convertions do not crash
1841c77
to
5928b12
Compare
5928b12
to
adba283
Compare
…epresentation conversions.
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.
Looks great, thank you!
@swift-ci please smoke test |
@swift-ci please test source compatibility release |
@xedin Source compatibility release test ok, this is ready to go? :) |
Thank you! |
Check representations of function type parameters are valid conversions on SILGen and diagnose if they not instead of letting them hit assertions and crashing the compiler.
cc @xedin @slavapestov :)
Resolves SR-12723.