-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[C++ Interop] Support C++ parameters in Obj-C++ methods. #60774
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
needs to be tested :) |
The test I am using is at #60638, but because of the missing As we had talked, I will try to merge both |
I feel like we could unify these two functions. But, not something you have to do in this patch. This LGTM (of course with some tests). |
60843c5
to
9e17a8c
Compare
@swift-ci please smoke test |
Version with the common code extracted and a test for the Obj-C++ methods having the right parameters. The test includes a couple of FIXME for those missing |
9e17a8c
to
d62095a
Compare
@plotfi: I have split the change in smaller commits that hopefully can be reviewed independently to see the evolution of the code. |
@swift-ci please test |
Nice work Daniel. Once this set of changes is landed I can look at changing @in to @in_guaranteed. |
d62095a
to
5f03904
Compare
@swift-ci please test |
@drodriguez can you mark the change |
What does the "i" means? It is not completely NFC though, so I didn't want to mark it as such. But if I rewrite the stack I can change the commit message (I don't want to restart the testing in case it is something cosmetic, but I am sure there will be more feedback later). |
"intended" |
@drodriguez Could it be possible to break up |
Once I study the non-NFC part of this patch I will probably merge. the NFC parts for the most part LGTM. The tests also look inline with what I was going for. @zoecarver @hyp do you have any other feedback on this PR? |
I don't completely understand what you are asking me to do. Do you want me to move the pieces that support method parameters without calling it from the |
That is a good point, don't worry about that. I think things look good as it is. |
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.
Thanks, this is good to go. Let's also run source compat suite.
@swift-ci please test source compatibility |
@swift-ci please test source compatibility |
// CHECK-SAME: : $@convention(c) (OptionsStruct) -> @out OptionsConsumerCxx | ||
|
||
// COM: FIXME: should it be @in_guaranteed OptionStruct? | ||
// CHECK: [[FN6:%[0-9]+]] = function_ref @_ZN18OptionsConsumerCxx12doOtherThingERK13OptionsStruct : $@convention(cxx_method) (@in OptionsStruct, @inout OptionsConsumerCxx) -> Float |
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.
Is this passing on Windows?
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 there's a requires objc at the top.
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 know what would change for Windows. The mangling?
As a later PR I can split the test into a pure C++ one and a Obj-C++ one, so at least part of the test runs in Linux and Windows. I don't have a Windows machine anymore, but I can check that Linux is consistent with Darwin.
@beccadax would you mind looking over these changes (as they touch objc method importing)? |
The same piece of code was repeated in two different methods: `importFunctionParameterList` and `importMethodParamsAndReturnType`. To avoid repetition and simplify the later refactoring extract the code into a helper. The code in the two methods was happening in slightly different places, but the modified code should still be equivalent and should not introduce functional differences.
The methods `importFunctionParameterList` and `importMethodParamsAndReturnType` share a similar piece of code to create the parameter information from the results of finding the parameter type. In order to simplify the later refactor and to make the changes clearer, extract the common code into a helper function and call it from both methods, replacing the duplicated code.
To make the refactor of the methods `importFunctionParameterList` and `importMethodParamsAndReturnType` easier in a later commit, move some lines that were intermixed with the common code earlier in each of those two methods. Even if some lines move earlier, there should be no difference functionally.
Extract a helper method `importParameterType` from the `importFunctionParameterList` code. This new helper only deals with function parameters, but the final intention is that it will be shared code with the code that import method parameters. The only functional difference introduced is that before, some of the branches will not have added an extra diagnostic about parameters failing to import, while this version adds those diagnostics consistently for any case.
Adapt the helper for figuring out parameter types for functions with the code exclusive for figuring out method parameters. This includes special code for handling dictionary subscripts, error parameters and completion handlers. The function parameters behaviour should not be modified, since in order to import function parameters all of the new pieces of code should be skipped following the value of the flags passed into the helper. For method parameters, there is extensive changes, specially in the cases of importing Obj-C++ methods that use C++ types, which were supported for functions, but not so much for methods.
Use capitalization correctly in one variable name, and use the name used in other parts of the file for a parameter.
Add a test case that checks the behaviour introduced during the refactor of `importFunctionParameterList` and `importMethodParamsAndReturnType`. The test checks that both Obj-C++ methods and C++ functions treat `const T&` parameters in the same way.
Instead of having out parameters for a couple of flags, create a small struct with the type and the flags and return that struct inside the Optional of importParameterType. Additionally change the naming of some variables to make the function and method code more similar.
51c1b03
to
abd3c16
Compare
@swift-ci please test |
@swift-ci please test source compatibility |
@beccadax @zoecarver Is there more to look at for this PR before merging? |
I am going to merge this in order to unblock other changes after this. If there's a problem, we should be able to fix forward or if there's a very big problem, reverting is also fine. Hope I do not disrupt anyone's work. |
Merging @drodriguez. Will accept post commit reviews @zoecarver @beccadax. Thanks. |
_ = OptionsConsumerCxx.doThing(a) | ||
} | ||
|
||
// RUN: %target-swift-ide-test -print-module -module-to-print=ConstRefParameter -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop -enable-objc-interop | %FileCheck -check-prefix=CHECK-IDE-TEST %s |
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 should go at the top of the file.
|
||
// CHECK-IDE-TEST: class OptionsConsumerObjC | ||
// CHECK-IDE-TEST: init(options: OptionsStruct) | ||
// COM: FIXME: should it be consumer(options:)? |
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 see why?
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.
According to https://github.com/apple/swift/blob/main/docs/CToSwiftNameTranslation.md#factory-initializers for a factory initializer the "with" should be dropped. I don't know why it is not happening here.
But also, there's a phrase that says "If a factory initializer turns out to have the same imported name as an available designated initializer, or a non-inherited factory initializer has the same imported name as an available convenience initializer, the factory initializer is marked unavailable to resolve ambiguities." which also should had happen here, but it doesn't (consumer
should have turn into init
).
Something is wonky here, but I am not sure what exactly is failing.
|
||
// RUN: %target-swift-frontend -c -enable-experimental-cxx-interop -enable-objc-interop -I %S/Inputs %s -emit-silgen -o - | %FileCheck %s | ||
|
||
// COM: FIXME: should it be @in_guaranteed OptionsStruct? https://github.com/apple/swift/issues/60601 |
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 one of these comments is sufficient.
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.
Most of the comments are removed in Puyan's next PR (actually, this one is not actually removed). I will review after his PR and try to remove duplicated comments.
// CHECK-IDE-TEST: mutating func doOtherThing(_ options: OptionsStruct) -> Float | ||
|
||
|
||
// RUN: %target-swift-frontend -c -enable-experimental-cxx-interop -enable-objc-interop -I %S/Inputs %s -emit-silgen -o - | %FileCheck %s |
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.
Again this should go at the top of the file.
static OptionsConsumerCxx build(const OptionsStruct &options); | ||
static int doThing(const OptionsStruct &options); | ||
float doOtherThing(const OptionsStruct &options); |
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.
These method names aren't particularly helpful. Maybe you can rename them "getIntOption" and "getFloatOption" or "staticMethod" and "instanceMethod" depending on why they are interesting test cases.
isa<clang::TemplateTypeParmType>(paramTy->getPointeeType())) { | ||
auto templateParamType = | ||
cast<clang::TemplateTypeParmType>(paramTy->getPointeeType()); | ||
swiftParamTy = findGenericTypeInGenericDecls( |
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 like this patch enables a lot of new behavior for Objective-C++ methods (for example, templated methods, if those are even allowed). Can you add some more tests? Otherwise people will use them and we'll have no idea if they work or not.
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 will try to move the RUN
lines at the top of the file after Puyan merges his PR. I did not know there's a preferred style (I prefer to have them close to the check lines, if possible).
|
||
// CHECK-IDE-TEST: class OptionsConsumerObjC | ||
// CHECK-IDE-TEST: init(options: OptionsStruct) | ||
// COM: FIXME: should it be consumer(options:)? |
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.
According to https://github.com/apple/swift/blob/main/docs/CToSwiftNameTranslation.md#factory-initializers for a factory initializer the "with" should be dropped. I don't know why it is not happening here.
But also, there's a phrase that says "If a factory initializer turns out to have the same imported name as an available designated initializer, or a non-inherited factory initializer has the same imported name as an available convenience initializer, the factory initializer is marked unavailable to resolve ambiguities." which also should had happen here, but it doesn't (consumer
should have turn into init
).
Something is wonky here, but I am not sure what exactly is failing.
|
||
// RUN: %target-swift-frontend -c -enable-experimental-cxx-interop -enable-objc-interop -I %S/Inputs %s -emit-silgen -o - | %FileCheck %s | ||
|
||
// COM: FIXME: should it be @in_guaranteed OptionsStruct? https://github.com/apple/swift/issues/60601 |
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.
Most of the comments are removed in Puyan's next PR (actually, this one is not actually removed). I will review after his PR and try to remove duplicated comments.
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.
Retrospective review: Looks generally good. I have one concern that doesn’t seem to have been discussed yet.
@@ -2904,7 +2911,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( | |||
} | |||
|
|||
// Special case for NSDictionary's subscript. | |||
ImportTypeKind importKind = ImportTypeKind::Parameter; |
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.
Previously, there were a few paths through this code where it would always end up with ImportTypeKind::Parameter
. Are you sure you’ve preserved this behavior?
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 was a difference between the importMethodParamsAndReturnType
and importFunctionParameterList
that were in different places, but had the same results.
(I will quote the old lines in the rest of the text)
In importFunctionParameterList
in set in 2257-2261, almost being the first thing done in the method, but importKind
was not used until 2326 inside the check for !swiftParamTy
.
In importMethodParamsAndReturnType
is set in 2907 and only overwritten in 2937-2940 inside another !swiftParamTy
check (in this case an else if
, not a naked if
). The lines 2937-2940 are the same as the lines 2258-2261, and I don't think there's any change in param
that might change the result of those lines being together with the first line or separated.
From my reading of the code it seemed that the result in importKind
only depends on the initial (constant) value of param
, and it was not changing over the execution of the method. That's why it was extracted into a stateless helper and move closer to its usage.
I might have not seen some detail of how variables evolve, but I think the code should still create the same results.
importMethodParamsAndReturnType
andimportFunctionParameterList
share a lot of code but differed in how they treated C++ types.
Extract the common code and merge the differences in code between the
two functions into one single function and use it from both places. At the
end it needs also a small function to account for the slightly different way
Obj-C methods deal with error and completion callbacks.
NOTE: Even if
const T&
parameters are now correctly imported asT
atthe Swift level, in the case of initializers they are not correctly
imported as
@in T
and a crash will occur when using them.Relates to #60638
/cc @plotfi @bulbazord