Skip to content

[cxx-interop] Allow importing templated functions when template args do not appear in function signature #39535

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 1 commit into from
Oct 7, 2021

Conversation

guitard0g
Copy link

Currently if we try to import a templated function when the template parameters do not appear in the function signature, the corresponding Swift function will have extra unused generic parameters, which means we can't call those functions. This patch fixes the problem by making those template params into explicit metatype function parameters to the corresponding Swift function. E.g.

template <typename T>
void foo()

becomes:

func foo<T>(T: T.Type) 

instead of:

func foo<T>() // can't be called

This extra argument is only used to deduce the generic type needed to specialize the C++ function. The corresponding function call made under the hood will cut out the extra argument and forward along the proper parameters to the C++ function.

@guitard0g
Copy link
Author

WIP because there seems to be some wonkiness with how this interacts with default template arguments, still investigating a fix there.

@zoecarver zoecarver added the c++ interop Feature: Interoperability with C++ label Oct 5, 2021
Copy link
Contributor

@zoecarver zoecarver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What a great patch! Thank you, Josh.

I really like how you commented all the code you added so it's super easy to understand and follow. Also, thanks for factoring out that lambda into a general helper function.

I have one or two small nits, but overall, this patch seems good to me :)

bool shouldCheckResultType) -> bool {
auto paramDecl = genericParam->getClangDecl();
auto templateTypeParam = cast<clang::TemplateTypeParmDecl>(paramDecl);
// TODO: This won't work when we support importing dependent types. we'll
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's link this to the SR: XXXX.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, meant to actually give you the SR. Just update the TODO to read TODO(SR-13809):. This way we can grep for the SR and find all the places we need to update whenever we add support for dependent types.

@@ -109,7 +109,7 @@ Solution::computeSubstitutions(GenericSignature sig,
lookupConformanceFn);
}

static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate(
static ValueDecl *generateDeclForSpecializedCXXFunctionTemplate(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know I named this function, but it's kind of ugly, so while you're updating the signature maybe change it to generateSpecializedCXXFunctionTemplate? WDYT?

// metatype arguments to aid in typechecking, but they shouldn't be forwarded to
// the corresponding C++ function.
static std::pair<BraceStmt *, bool>
synthesizeForwardingThunkBody(AbstractFunctionDecl *afd, void *context) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in this patch, but at some point we should move all synthesizers to their own file. They just take up space right now and clutter the files they're scattered across.

templateTypeParamNotUsedInSignature(T: Int.self)
multiTemplateTypeParamNotUsedInSignature(T: Float.self, U: Int.self)
multiTemplateTypeParamNotUsedInSignatureWithUnrelatedParams(1, 1, T: Int32.self, U: Int.self)
let _: Int = templateTypeParamUsedInReturnType(10)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add an expectEquals somewhere in both of these tests. Otherwise (very theoretically), they might just get optimized away. Also it's not a bad idea to just test that the correct thing is returned and there wasn't an argument mismatch or something.

@zoecarver
Copy link
Contributor

@guitard0g let me know if you need help running the bots.

Copy link
Contributor

@egorzhdan egorzhdan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach looks great to me! I only noticed one small issue that prevents the C++ stdlib from being imported.

@guitard0g guitard0g force-pushed the tparam-not-used-in-fsig branch from 2fa8285 to d81a5c3 Compare October 6, 2021 04:55
@guitard0g guitard0g changed the title [WIP][cxx-interop] Allow importing templated functions when template args do not appear in function signature [cxx-interop] Allow importing templated functions when template args do not appear in function signature Oct 6, 2021
@guitard0g
Copy link
Author

@swift-ci please test

@guitard0g guitard0g force-pushed the tparam-not-used-in-fsig branch from d81a5c3 to d2c68cc Compare October 6, 2021 05:00
@guitard0g
Copy link
Author

@swift-ci please test

@guitard0g
Copy link
Author

@egorzhdan @zoecarver Thanks for the review! I believe I've addressed all the comments in the most recent revision. It changed a decent bit because I realized there were some quirks with making sure we manually invoke the generic substitutions on the signature of the synthesized thunk. Should be ready for another round of reviews.

Copy link
Contributor

@zoecarver zoecarver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚢 it

(I left three very small nits. All are optional.)

static ValueDecl *generateSpecializedCXXFunctionTemplate(
ASTContext &ctx, AbstractFunctionDecl *oldDecl, SubstitutionMap subst,
clang::FunctionDecl *specialized) {
auto newFnTypeAndParams = substituteFunctionTypeAndParamList(ctx, oldDecl, subst);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish we could use auto [a, b] = 😢

// exist in the resulting specialized FuncDecl. Note that this doesn't
// affect constructors because all template params for a constructor
// must be in the function signature by design.
continue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think various methods/static methods might take a meta type. We need to verify if this will break that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests are passing, so I guess this isn't an issue.

@zoecarver
Copy link
Contributor

Swift Test Windows Platform — Build failed.

Now you see why I'm so excited about #36082 :P

Copy link
Contributor

@egorzhdan egorzhdan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

in the function signature by adding explicit metatype parameters to
the function signature.
@guitard0g guitard0g force-pushed the tparam-not-used-in-fsig branch from d2c68cc to f433ac2 Compare October 6, 2021 20:35
@guitard0g
Copy link
Author

@swift-ci please smoke test and merge

@swift-ci swift-ci merged commit b69eac9 into swiftlang:main Oct 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ interop Feature: Interoperability with C++
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants